gl: most of opengl plugin has moved to -base, keep mixer bits in -bad for now

Since they rely on GstVideoAggregator.

Fix detection of things again, and Meson
This commit is contained in:
Tim-Philipp Müller 2017-12-11 14:20:59 +00:00
parent 769a21d0bb
commit ee589cd337
74 changed files with 42 additions and 19162 deletions

View file

@ -1899,6 +1899,8 @@ AG_GST_CHECK_FEATURE(GL, [gl elements], gl, [
dnl HAVE_GL="yes"
dnlfi
])
dnl FIXME
AM_CONDITIONAL(USE_OPENGL, false)
dnl *** gtk+ ***
HAVE_GTK3_GL="no"
@ -2705,6 +2707,7 @@ ext/faad/Makefile
ext/fdkaac/Makefile
ext/flite/Makefile
ext/fluidsynth/Makefile
ext/gl/Makefile
ext/gsm/Makefile
ext/hls/Makefile
ext/iqa/Makefile

View file

@ -1,164 +1,52 @@
plugin_LTLIBRARIES = libgstopengl.la
plugin_LTLIBRARIES = libgstopenglmixers.la
libgstopengl_la_SOURCES = \
# These have to stay in -bad until we can move GstVideoAggregator to -base
libgstopenglmixers_la_SOURCES = \
gstopengl.c \
gstglbasemixer.c \
gstgluploadelement.c \
gstgldownloadelement.c \
gstglcolorconvertelement.c \
gstglfilterbin.c \
gstglmixerbin.c \
gstglsinkbin.c \
gstglsrcbin.c \
gstglimagesink.c \
gstglfiltercube.c \
gstgleffects.c \
effects/gstgleffectscurves.c \
effects/gstgleffectssources.c \
effects/gstgleffectidentity.c \
effects/gstgleffectmirror.c \
effects/gstgleffectsqueeze.c \
effects/gstgleffectstretch.c \
effects/gstgleffectfisheye.c \
effects/gstgleffecttwirl.c \
effects/gstgleffectbulge.c \
effects/gstgleffecttunnel.c \
effects/gstgleffectsquare.c \
effects/gstgleffectlumatocurve.c \
effects/gstgleffectrgbtocurve.c \
effects/gstgleffectsin.c \
effects/gstgleffectxray.c \
effects/gstgleffectglow.c \
effects/gstgleffectblur.c \
effects/gstgleffectsobel.c \
effects/gstgleffectlaplacian.c \
gstglcolorscale.c \
gstglcolorbalance.c \
gstglmosaic.c \
gstglmixer.c \
gstglvideomixer.c \
gstglfiltershader.c \
gstglfilterapp.c \
gstglviewconvert.c \
gstglstereosplit.c \
gstgldeinterlace.c \
gstglmixerbin.c \
gstglstereomix.c \
gltestsrc.c \
gstgltestsrc.c \
gstglutils.c
gstglutils.c \
gstglvideomixer.c
noinst_HEADERS = \
gstglbasemixer.h \
gstgluploadelement.h \
gstgldownloadelement.h \
gstglcolorconvertelement.h \
gstglfilterbin.h \
gstglmixerbin.h \
gstglsinkbin.h \
gstglsrcbin.h \
gstglimagesink.h \
gstglfiltercube.h \
gstgleffects.h \
effects/gstgleffectssources.h \
gstglcolorscale.h \
gstglcolorbalance.h \
gstglmosaic.h \
gstglmixer.h \
gstglvideomixer.h \
gstglfiltershader.h \
gstglfilterapp.h \
gstglstereosplit.h \
gstglmixerbin.h \
gstglstereomix.h \
gstgldeinterlace.h \
gstglviewconvert.h \
gltestsrc.h \
gstgltestsrc.h \
gstglutils.h
gstglutils.h \
gstglvideomixer.h
# full opengl required
if USE_OPENGL
libgstopengl_la_SOURCES += \
gstglfilterglass.c \
gstglmosaic.c
noinst_HEADERS += \
gstglfilterglass.h \
gstglmosaic.h \
effects/gstgleffectscurves.h \
effects/gstgleffectlumatocurve.h
if HAVE_PNG
libgstopengl_la_SOURCES += \
gstgldifferencematte.c
noinst_HEADERS += \
gstgldifferencematte.h
endif
libgstopenglmixers_la_SOURCES += gstglmosaic.c
noinst_HEADERS += gstglmosaic.h
endif
if HAVE_GRAPHENE
libgstopengl_la_SOURCES += \
gstgltransformation.c \
gstglvideoflip.c
noinst_HEADERS += \
gstgltransformation.h \
gstglvideoflip.h
endif
if HAVE_JPEG
if HAVE_PNG
libgstopengl_la_SOURCES += \
gstgloverlay.c
noinst_HEADERS += \
gstgloverlay.h
endif
endif
if HAVE_WINDOW_COCOA
libgstopengl_la_SOURCES += \
caopengllayersink.m
noinst_HEADERS += \
caopengllayersink.h
endif
libgstopengl_la_OBJCFLAGS = \
-I$(top_srcdir)/gst-libs \
-I$(top_builddir)/gst-libs \
-fobjc-arc \
$(GST_OBJCFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_CONTROLLER_CFLAGS) \
$(GL_OBJCFLAGS)
# FIXME: can we remove GL flags here?
# 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 \
-I$(top_builddir)/gst-libs \
$(GST_CFLAGS) \
$(GST_BASE_CFLAGS) \
libgstopenglmixers_la_CFLAGS = \
$(GST_PLUGINS_BAD_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_CONTROLLER_CFLAGS) \
$(GL_CFLAGS) \
$(LIBPNG_CFLAGS) \
$(GRAPHENE_CFLAGS)
$(GST_CFLAGS) \
$(GL_CFLAGS)
libgstopengl_la_LIBADD = \
$(top_builddir)/gst-libs/gst/gl/libgstgl-$(GST_API_VERSION).la \
$(top_builddir)/gst-libs/gst/video/libgstbadvideo-$(GST_API_VERSION).la \
libgstopenglmixers_la_LIBADD = \
$(top_builddir)/gst-libs/gst/video/libgstbadvideo-@GST_API_VERSION@.la \
$(GST_PLUGINS_BASE_LIBS) \
-lgstgl-@GST_API_VERSION@
$(GST_BASE_LIBS) \
$(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
-lgstpbutils-$(GST_API_VERSION) \
$(GST_CONTROLLER_LIBS) \
$(GST_LIBS) \
$(GL_LIBS) \
$(LIBPNG_LIBS) \
$(JPEG_LIBS) \
$(LIBM) \
$(GRAPHENE_LIBS)
libgstopengl_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstopengl_la_LIBTOOLFLAGS = --tag=CC
$(LIBM)
libgstopenglmixers_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstopenglmixers_la_LIBTOOLFLAGS = --tag=CC

View file

@ -1,98 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __CA_OPENGL_LAYER_SINK_H__
#define __CA_OPENGL_LAYER_SINK_H__
#include <gst/gst.h>
#include <gst/video/gstvideosink.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
#include <gst/gl/gstglfuncs.h>
#include <gst/gl/cocoa/gstglcaopengllayer.h>
G_BEGIN_DECLS
#define GST_TYPE_CA_OPENGL_LAYER_SINK \
(gst_ca_opengl_layer_sink_get_type())
#define GST_CA_OPENGL_LAYER_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CA_OPENGL_LAYER_SINK,GstCAOpenGLLayerSink))
#define GST_CA_OPENGL_LAYER_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CA_OPENGL_LAYER_SINK,GstCAOpenGLLayerSinkClass))
#define GST_IS_CA_OPENGL_LAYER_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CA_OPENGL_LAYER_SINK))
#define GST_IS_CA_OPENGL_LAYER_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CA_OPENGL_LAYER_SINK))
typedef struct _GstCAOpenGLLayerSink GstCAOpenGLLayerSink;
typedef struct _GstCAOpenGLLayerSinkClass GstCAOpenGLLayerSinkClass;
struct _GstCAOpenGLLayerSink
{
GstVideoSink video_sink;
/* caps */
GstVideoInfo info;
GstCaps *gl_caps;
/* gl state */
GstGLDisplay *display;
GstGLContext *other_context;
GstGLContext *context;
guint next_tex;
GstBuffer *next_buffer;
GstBuffer *next_sync;
gpointer layer;
gboolean keep_aspect_ratio;
/* avoid replacing the stored_buffer while drawing */
GMutex drawing_lock;
GstBuffer *stored_buffer;
GstBuffer *stored_sync;
GLuint redisplay_texture;
gboolean caps_change;
guint window_width;
guint window_height;
/* gl state */
GstGLShader *redisplay_shader;
GLuint vao;
GLuint vertex_buffer;
GLuint vbo_indices;
GLint attr_position;
GLint attr_texture;
};
struct _GstCAOpenGLLayerSinkClass
{
GstVideoSinkClass video_sink_class;
};
GType gst_ca_opengl_layer_sink_get_type(void);
GType gst_ca_opengl_layer_sink_bin_get_type (void);
G_END_DECLS
#endif /* __CA_OPENGL_LAYER_SINK__ */

File diff suppressed because it is too large Load diff

View file

@ -1,68 +0,0 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
* Copyright (C) 2015 Michał Dębski <debski.mi.zd@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 float *
gst_gl_effects_blur_kernel (void)
{
/* gaussian kernel (well, actually vector), size 9, standard
* deviation 3.0 */
/* FIXME: make this a runtime property */
static gfloat *kernel = NULL;
if (G_UNLIKELY (NULL == kernel)) {
/* 3x3 matrix */
kernel = g_malloc (sizeof (gfloat) * 9);
fill_gaussian_kernel (kernel, 7, 3.f);
}
return kernel;
}
void
gst_gl_effects_blur (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "hconv0",
hconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "gauss_width",
GST_VIDEO_INFO_WIDTH (&filter->in_info));
gst_gl_shader_set_uniform_1fv (shader, "kernel", 7,
gst_gl_effects_blur_kernel ());
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->midtexture[0], shader);
shader = gst_gl_effects_get_fragment_shader (effects, "vconv0",
vconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "gauss_height",
GST_VIDEO_INFO_HEIGHT (&filter->in_info));
gst_gl_shader_set_uniform_1fv (shader, "kernel", 7,
gst_gl_effects_blur_kernel ());
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[0],
effects->outtexture, shader);
}

View file

@ -1,36 +0,0 @@
/*
* 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"
void
gst_gl_effects_bulge (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "bulge",
bulge_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -1,36 +0,0 @@
/*
* 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"
void
gst_gl_effects_fisheye (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "fisheye",
fisheye_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -1,86 +0,0 @@
/*
* 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];
void
gst_gl_effects_glow (GstGLEffects * effects)
{
const GstGLFuncs *gl = GST_GL_BASE_FILTER (effects)->context->gl_vtable;
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
if (!kernel_ready) {
fill_gaussian_kernel (gauss_kernel, 7, 10.0);
kernel_ready = TRUE;
}
/* threshold */
shader = gst_gl_effects_get_fragment_shader (effects, "luma_threshold",
luma_threshold_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->midtexture[0], shader);
/* blur */
shader = gst_gl_effects_get_fragment_shader (effects, "hconv7",
hconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 7, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "gauss_width",
GST_VIDEO_INFO_WIDTH (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[0],
effects->midtexture[1], shader);
shader = gst_gl_effects_get_fragment_shader (effects, "vconv7",
vconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 7, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "gauss_height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[1],
effects->midtexture[2], shader);
/* add blurred luma to intexture */
shader = gst_gl_effects_get_fragment_shader (effects, "sum",
sum_fragment_source_gles2);
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE2);
gl->BindTexture (GL_TEXTURE_2D,
gst_gl_memory_get_texture_id (effects->intexture));
gst_gl_shader_set_uniform_1f (shader, "alpha", 1.0f);
gst_gl_shader_set_uniform_1i (shader, "base", 2);
gl->ActiveTexture (GL_TEXTURE1);
gl->BindTexture (GL_TEXTURE_2D,
gst_gl_memory_get_texture_id (effects->midtexture[2]));
gst_gl_shader_set_uniform_1f (shader, "beta", (gfloat) 1 / 3.5f);
gst_gl_shader_set_uniform_1i (shader, "blend", 1);
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[2],
effects->outtexture, shader);
}

View file

@ -1,49 +0,0 @@
/*
* 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"
void
gst_gl_effects_identity (GstGLEffects * effects)
{
GstGLContext *context = GST_GL_BASE_FILTER (effects)->context;
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = g_hash_table_lookup (effects->shaderstable, "identity0");
if (!shader) {
GError *error = NULL;
if (!(shader = gst_gl_shader_new_default (context, &error))) {
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("Failed to initialize identity shader: %s", error->message), (NULL));
return;
}
g_hash_table_insert (effects->shaderstable, (gchar *) "identity0", shader);
}
gst_gl_shader_use (shader);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -1,52 +0,0 @@
/*
* GStreamer
* Copyright (C) 2008-2010 Filippo Argiolas <filippo.argiolas@gmail.com>
* Copyright (C) 2015 Michał Dębski <debski.mi.zd@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 gfloat kernel[9] = {
0.0, -1.0, 0.0,
-1.0, 4.0, -1.0,
0.0, -1.0, 0.0
};
void
gst_gl_effects_laplacian (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "conv0",
conv9_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "height",
GST_VIDEO_INFO_HEIGHT (&filter->in_info));
gst_gl_shader_set_uniform_1f (shader, "width",
GST_VIDEO_INFO_WIDTH (&filter->in_info));
gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, kernel);
gst_gl_shader_set_uniform_1i (shader, "invert", effects->invert);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -1,92 +0,0 @@
/*
* 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,
const GstGLEffectsCurve * curve, gint curve_index, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLContext *context = GST_GL_BASE_FILTER (effects)->context;
GstGLFilter *filter = GST_GL_FILTER (effects);
const GstGLFuncs *gl = context->gl_vtable;
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "luma_to_curve",
luma_to_curve_fragment_source_gles2);
if (!shader)
return;
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (context)) {
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
}
#endif
if (effects->curve[curve_index] == 0) {
/* this parameters are needed to have a right, predictable, mapping */
gl->GenTextures (1, &effects->curve[curve_index]);
gl->BindTexture (GL_TEXTURE_2D, effects->curve[curve_index]);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
curve->width, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, curve->pixel_data);
}
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE2);
gl->BindTexture (GL_TEXTURE_2D, effects->curve[curve_index]);
gst_gl_shader_set_uniform_1i (shader, "curve", 2);
gst_gl_filter_render_to_target_with_shader (filter, in_tex, out_tex, shader);
}
void
gst_gl_effects_heat (GstGLEffects * effects)
{
gst_gl_effects_luma_to_curve (effects, &heat_curve,
GST_GL_EFFECTS_CURVE_HEAT, effects->intexture, effects->outtexture);
}
void
gst_gl_effects_sepia (GstGLEffects * effects)
{
gst_gl_effects_luma_to_curve (effects, &sepia_curve,
GST_GL_EFFECTS_CURVE_SEPIA, effects->intexture, effects->outtexture);
}
void
gst_gl_effects_luma_xpro (GstGLEffects * effects)
{
gst_gl_effects_luma_to_curve (effects, &luma_xpro_curve,
GST_GL_EFFECTS_CURVE_LUMA_XPRO, effects->intexture, effects->outtexture);
}

View file

@ -1,35 +0,0 @@
/*
* 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,
const GstGLEffectsCurve *curve,
gint curve_index,
GstGLMemory *in_tex,
GstGLMemory *out_tex);
G_END_DECLS
#endif /* __GST_GL_LUMA_TO_CURVE_H__ */

View file

@ -1,36 +0,0 @@
/*
* 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"
void
gst_gl_effects_mirror (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "mirror",
mirror_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -1,78 +0,0 @@
/*
* 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,
const GstGLEffectsCurve * curve, gint curve_index, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLContext *context = GST_GL_BASE_FILTER (effects)->context;
GstGLFilter *filter = GST_GL_FILTER (effects);
const GstGLFuncs *gl = context->gl_vtable;
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "rgb_to_curve",
rgb_to_curve_fragment_source_gles2);
if (!shader)
return;
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (context)) {
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
}
#endif
if (effects->curve[curve_index] == 0) {
/* this parameters are needed to have a right, predictable, mapping */
gl->GenTextures (1, &effects->curve[curve_index]);
gl->BindTexture (GL_TEXTURE_2D, effects->curve[curve_index]);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
curve->width, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, curve->pixel_data);
}
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE2);
gl->BindTexture (GL_TEXTURE_2D, effects->curve[curve_index]);
gst_gl_shader_set_uniform_1i (shader, "curve", 2);
gst_gl_filter_render_to_target_with_shader (filter, in_tex, out_tex, shader);
}
void
gst_gl_effects_xpro (GstGLEffects * effects)
{
gst_gl_effects_rgb_to_curve (effects, &xpro_curve, GST_GL_EFFECTS_CURVE_XPRO,
effects->intexture, effects->outtexture);
}

View file

@ -1,210 +0,0 @@
/*
* 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 "gstgleffectscurves.h"
/* CURVE for the heat signature effect */
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",
};
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 */
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",
};
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",
};
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",
};

View file

@ -1,47 +0,0 @@
/*
* 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__
#include <glib.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 */
extern const GstGLEffectsCurve xpro_curve;
extern const GstGLEffectsCurve luma_xpro_curve;
/* CURVE for the heat signature effect */
extern const GstGLEffectsCurve heat_curve;
extern const GstGLEffectsCurve sepia_curve;
extern const GstGLEffectsCurve xray_curve;
#endif

View file

@ -1,36 +0,0 @@
/*
* 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"
void
gst_gl_effects_sin (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "sin",
sin_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -1,61 +0,0 @@
/*
* GStreamer
* Copyright (C) 2008-2010 Filippo Argiolas <filippo.argiolas@gmail.com>
* Copyright (C) 2015 Michał Dębski <debski.mi.zd@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"
void
gst_gl_effects_sobel (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "desat0",
desaturate_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->midtexture[0], shader);
shader = gst_gl_effects_get_fragment_shader (effects, "hconv0",
sep_sobel_hconv3_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[0],
effects->midtexture[1], shader);
shader = gst_gl_effects_get_fragment_shader (effects, "vconv0",
sep_sobel_vconv3_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "width",
GST_VIDEO_INFO_WIDTH (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[1],
effects->midtexture[0], shader);
shader = gst_gl_effects_get_fragment_shader (effects, "len0",
sep_sobel_length_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1i (shader, "invert", effects->invert);
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[0],
effects->outtexture, shader);
}

View file

@ -1,36 +0,0 @@
/*
* 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"
void
gst_gl_effects_square (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "square",
square_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -1,36 +0,0 @@
/*
* 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"
void
gst_gl_effects_squeeze (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "squeeze",
squeeze_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -1,548 +0,0 @@
/*
* 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* */
/* Mirror effect */
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;"
"}";
const gchar *mirror_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"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);"
"}";
const gchar *squeeze_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord = texturecoord - 0.5;"
/* Add a very small value to length otherwise it could be 0 */
" float r = length (normcoord)+0.01;"
" r = pow(r, 0.40)*1.3;"
" normcoord = normcoord / r;"
" texturecoord = (normcoord + 0.5);"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *stretch_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" normcoord *= 2.0 - smoothstep(0.0, 0.35, r);"
" texturecoord = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *tunnel_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord;"
/* little trick with normalized coords to obtain a circle with
* rect textures */
" normcoord = (texturecoord - 0.5);"
" float r = length(normcoord);"
" if (r > 0.0)"
" normcoord *= clamp (r, 0.0, 0.275) / r;"
" texturecoord = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *fisheye_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" normcoord *= r * 1.41421;" /* sqrt (2) */
" texturecoord = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *twirl_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.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;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *bulge_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" normcoord *= smoothstep (-0.05, 0.25, r);"
" texturecoord = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *square_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.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;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
const gchar *luma_threshold_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" 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_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform bool invert;"
"void main () {"
" vec4 g = texture2D (tex, v_texcoord.xy);"
/* 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_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec4 color = texture2D (tex, v_texcoord.xy);"
" 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_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform float width;"
"void main () {"
" float w = 1.0 / width;"
" vec2 texturecoord[3];"
" texturecoord[1] = v_texcoord.xy;"
" 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_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform float height;"
"void main () {"
" float h = 1.0 / height;"
" vec2 texturecoord[3];"
" texturecoord[1] = v_texcoord.xy;"
" 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);"
"}";
const gchar *hconv7_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform float kernel[7];"
"uniform float gauss_width;"
"void main () {"
" float w = 1.0 / gauss_width;"
" vec2 texturecoord[7];"
" texturecoord[3] = v_texcoord.xy;"
" 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_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform float kernel[7];"
"uniform float gauss_height;"
"void main () {"
" float h = 1.0 / gauss_height;"
" vec2 texturecoord[7];"
" texturecoord[3] = v_texcoord.xy;"
" 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_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D base;"
"uniform sampler2D blend;"
"uniform float alpha;"
"uniform float beta;"
"void main () {"
" vec4 basecolor = texture2D (base, v_texcoord.xy);"
" vec4 blendcolor = texture2D (blend, v_texcoord.xy);"
" gl_FragColor = alpha * basecolor + beta * blendcolor;"
"}";
const gchar *multiply_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D base;"
"uniform sampler2D blend;"
"uniform float alpha;"
"void main () {"
" vec4 basecolor = texture2D (base, v_texcoord.xy);"
" vec4 blendcolor = texture2D (blend, v_texcoord.xy);"
" 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_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform sampler2D curve;"
"void main () {"
" vec2 texturecoord = v_texcoord.xy;"
" vec4 color = texture2D (tex, texturecoord);"
" float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));"
" color = texture2D (curve, vec2(luma, 0.0));"
" gl_FragColor = color;"
"}";
/* lut operations, map rgb to tex1d, see orange book (chapter 19) */
const gchar *rgb_to_curve_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform sampler2D curve;"
"void main () {"
" vec4 color = texture2D (tex, v_texcoord.xy);"
" vec4 outcolor;"
" outcolor.r = texture2D (curve, vec2(color.r, 0.0)).r;"
" outcolor.g = texture2D (curve, vec2(color.g, 0.0)).g;"
" outcolor.b = texture2D (curve, vec2(color.b, 0.0)).b;"
" outcolor.a = color.a;"
" gl_FragColor = outcolor;"
"}";
const gchar *sin_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"void main () {"
" vec4 color = texture2D (tex, vec2(v_texcoord.xy));"
" 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 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D base;"
"uniform sampler2D blend;"
"void main () {"
"vec4 basecolor = texture2D (base, v_texcoord);"
"vec4 blendcolor = texture2D (blend, v_texcoord);"
"vec4 white = vec4(1.0);"
"gl_FragColor = blendcolor + (1.0 - blendcolor.a) * basecolor;"
"}";
const gchar *texture_interp_fragment_source =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D base;"
"uniform sampler2D blend;"
"uniform sampler2D alpha;"
"void main () {"
" vec4 basecolor = texture2D (base, v_texcoord);"
" vec4 blendcolor = texture2D (blend, v_texcoord);"
" vec4 alphacolor = texture2D (alpha, v_texcoord);"
" gl_FragColor = (alphacolor * blendcolor) + (1.0 - alphacolor) * basecolor;"
"}";
const gchar *difference_fragment_source =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D saved;"
"uniform sampler2D current;"
"void main () {"
"vec4 savedcolor = texture2D (saved, v_texcoord);"
"vec4 currentcolor = texture2D (current, v_texcoord);"
"gl_FragColor = vec4 (step (0.12, length (savedcolor - currentcolor)));"
"}";
/* 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 */
const gchar *conv9_fragment_source_gles2 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord;"
"uniform sampler2D tex;"
"uniform float kernel[9];"
"uniform float width, height;"
"uniform bool invert;"
"void main () {"
" float w = 1.0 / width;"
" float h = 1.0 / height;"
" vec2 texturecoord[9];"
" texturecoord[4] = v_texcoord.xy;" /* 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;"
" vec3 sum = vec3 (0.0);"
" for (i = 0; i < 9; i++) { "
" vec4 neighbor = texture2D (tex, texturecoord[i]);"
" sum += neighbor.xyz * kernel[i];"
" }"
" gl_FragColor = vec4 (abs(sum - vec3(float(invert))), 1.0);"
"}";
/* *INDENT-ON* */

View file

@ -1,52 +0,0 @@
/*
* 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 *mirror_fragment_source_gles2;
extern const gchar *squeeze_fragment_source_gles2;
extern const gchar *stretch_fragment_source_gles2;
extern const gchar *fisheye_fragment_source_gles2;
extern const gchar *twirl_fragment_source_gles2;
extern const gchar *bulge_fragment_source_gles2;
extern const gchar *tunnel_fragment_source_gles2;
extern const gchar *square_fragment_source_gles2;
extern const gchar *luma_threshold_fragment_source_gles2;
extern const gchar *hconv7_fragment_source_gles2;
extern const gchar *vconv7_fragment_source_gles2;
extern const gchar *sum_fragment_source_gles2;
extern const gchar *luma_to_curve_fragment_source_gles2;
extern const gchar *rgb_to_curve_fragment_source_gles2;
extern const gchar *sin_fragment_source_gles2;
extern const gchar *desaturate_fragment_source_gles2;
extern const gchar *sep_sobel_hconv3_fragment_source_gles2;
extern const gchar *sep_sobel_vconv3_fragment_source_gles2;
extern const gchar *sep_sobel_length_fragment_source_gles2;
extern const gchar *multiply_fragment_source_gles2;
extern const gchar *conv9_fragment_source_gles2;
extern const gchar *interpolate_fragment_source;
extern const gchar *texture_interp_fragment_source;
extern const gchar *difference_fragment_source;
void fill_gaussian_kernel (float *kernel, int size, float sigma);
#endif /* __GST_GL_EFFECTS_SOURCES_H__ */

View file

@ -1,36 +0,0 @@
/*
* 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"
void
gst_gl_effects_stretch (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "stretch",
stretch_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -1,36 +0,0 @@
/*
* 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"
void
gst_gl_effects_tunnel (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "tunnel",
tunnel_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -1,36 +0,0 @@
/*
* 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"
void
gst_gl_effects_twirl (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
shader = gst_gl_effects_get_fragment_shader (effects, "twirl",
twirl_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->outtexture, shader);
}

View file

@ -1,124 +0,0 @@
/*
* 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];
void
gst_gl_effects_xray (GstGLEffects * effects)
{
const GstGLFuncs *gl = GST_GL_BASE_FILTER (effects)->context->gl_vtable;
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLShader *shader;
if (!kernel_ready) {
fill_gaussian_kernel (gauss_kernel, 7, 1.5);
kernel_ready = TRUE;
}
/* map luma to xray curve */
gst_gl_effects_luma_to_curve (effects, &xray_curve, GST_GL_EFFECTS_CURVE_XRAY,
effects->intexture, effects->midtexture[0]);
/* horizontal blur */
shader = gst_gl_effects_get_fragment_shader (effects, "hconv7",
hconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "gauss_width",
GST_VIDEO_INFO_WIDTH (&filter->in_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[0],
effects->midtexture[1], shader);
/* vertical blur */
shader = gst_gl_effects_get_fragment_shader (effects, "vconv7",
vconv7_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "gauss_height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[1],
effects->midtexture[2], shader);
/* 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 */
shader = gst_gl_effects_get_fragment_shader (effects, "desaturate",
desaturate_fragment_source_gles2);
gst_gl_filter_render_to_target_with_shader (filter, effects->intexture,
effects->midtexture[3], shader);
/* horizonal convolution */
shader = gst_gl_effects_get_fragment_shader (effects, "sobel_hconv3",
sep_sobel_hconv3_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "width",
GST_VIDEO_INFO_WIDTH (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[3],
effects->midtexture[4], shader);
/* vertical convolution */
shader = gst_gl_effects_get_fragment_shader (effects, "sobel_vconv3",
sep_sobel_vconv3_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1f (shader, "height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[4],
effects->midtexture[3], shader);
/* gradient length */
shader = gst_gl_effects_get_fragment_shader (effects, "sobel_length",
sep_sobel_length_fragment_source_gles2);
gst_gl_shader_use (shader);
gst_gl_shader_set_uniform_1i (shader, "invert", TRUE);
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[3],
effects->midtexture[4], shader);
/* multiply edges with the blurred image */
shader = gst_gl_effects_get_fragment_shader (effects, "multiply",
multiply_fragment_source_gles2);
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE2);
gl->BindTexture (GL_TEXTURE_2D,
gst_gl_memory_get_texture_id (effects->midtexture[2]));
gst_gl_shader_set_uniform_1i (shader, "base", 2);
gl->ActiveTexture (GL_TEXTURE1);
gl->BindTexture (GL_TEXTURE_2D,
gst_gl_memory_get_texture_id (effects->midtexture[4]));
gst_gl_shader_set_uniform_1f (shader, "alpha", (gfloat) 0.5f);
gst_gl_shader_set_uniform_1i (shader, "blend", 1);
gst_gl_filter_render_to_target_with_shader (filter, effects->midtexture[4],
effects->outtexture, shader);
}

File diff suppressed because it is too large Load diff

View file

@ -1,81 +0,0 @@
/* 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>
typedef struct _GstGLTestSrc GstGLTestSrc;
/**
* 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,
GST_GL_TEST_SRC_MANDELBROT
} GstGLTestSrcPattern;
#include "gstgltestsrc.h"
struct BaseSrcImpl {
GstGLTestSrc *src;
GstGLContext *context;
GstVideoInfo v_info;
};
struct SrcFuncs
{
GstGLTestSrcPattern pattern;
gpointer (*new) (GstGLTestSrc * src);
gboolean (*init) (gpointer impl, GstGLContext * context, GstVideoInfo * v_info);
gboolean (*fill_bound_fbo) (gpointer impl);
void (*free) (gpointer impl);
};
const struct SrcFuncs * gst_gl_test_src_get_src_funcs_for_pattern (GstGLTestSrcPattern pattern);
#endif

View file

@ -1,551 +0,0 @@
/* GStreamer
* Copyright (C) <2016> Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
* This file was modified from videobalance and converted to OpenGL
*/
/**
* SECTION:element-glcolorbalance
* @title: glcolorbalance
*
* Adjusts brightness, contrast, hue, saturation on a video stream.
*
* ## Example launch line
* |[
* gst-launch-1.0 videotestsrc ! glupload ! glcolorbalance saturation=0.0 ! glcolorconvert ! gldownload ! ximagesink
* ]| This pipeline converts the image to black and white by setting the
* saturation to 0.0.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/gl/gstglfuncs.h>
#include <gst/math-compat.h>
#include <gst/video/colorbalance.h>
#include "gstglcolorbalance.h"
GST_DEBUG_CATEGORY_STATIC (glcolorbalance_debug);
#define GST_CAT_DEFAULT glcolorbalance_debug
/* GstGLColorBalance properties */
#define DEFAULT_PROP_CONTRAST 1.0
#define DEFAULT_PROP_BRIGHTNESS 0.0
#define DEFAULT_PROP_HUE 0.0
#define DEFAULT_PROP_SATURATION 1.0
/* *INDENT-OFF* */
static const gchar *color_balance_frag =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"uniform float brightness;\n"
"uniform float contrast;\n"
"uniform float saturation;\n"
"uniform float hue;\n"
"varying vec2 v_texcoord;\n"
"uniform sampler2D tex;\n"
"#define from_yuv_bt601_offset vec3(-0.0625, -0.5, -0.5)\n"
"#define from_yuv_bt601_rcoeff vec3(1.164, 0.000, 1.596)\n"
"#define from_yuv_bt601_gcoeff vec3(1.164,-0.391,-0.813)\n"
"#define from_yuv_bt601_bcoeff vec3(1.164, 2.018, 0.000)\n"
"#define from_rgb_bt601_offset vec3(0.0625, 0.5, 0.5)\n"
"#define from_rgb_bt601_ycoeff vec3(0.256816, 0.504154, 0.0979137)\n"
"#define from_rgb_bt601_ucoeff vec3(-0.148246, -0.29102, 0.439266)\n"
"#define from_rgb_bt601_vcoeff vec3(0.439271, -0.367833, -0.071438)\n"
"#define PI 3.14159265\n"
"\n"
"vec3 yuv_to_rgb (vec3 val) {\n"
" vec3 rgb;\n"
" val += from_yuv_bt601_offset;\n"
" rgb.r = dot(val, from_yuv_bt601_rcoeff);\n"
" rgb.g = dot(val, from_yuv_bt601_gcoeff);\n"
" rgb.b = dot(val, from_yuv_bt601_bcoeff);\n"
" return rgb;\n"
"}\n"
"vec3 rgb_to_yuv (vec3 val) {\n"
" vec3 yuv;\n"
" yuv.r = dot(val.rgb, from_rgb_bt601_ycoeff);\n"
" yuv.g = dot(val.rgb, from_rgb_bt601_ucoeff);\n"
" yuv.b = dot(val.rgb, from_rgb_bt601_vcoeff);\n"
" yuv += from_rgb_bt601_offset;\n"
" return yuv;\n"
"}\n"
/* 224 = 256 - (256 - 240) - 16*/
"float luma_to_narrow (float luma) {\n"
" return (luma + 16.0 / 256.0) * 219.0 / 256.0;"
"}\n"
"float luma_to_full (float luma) {\n"
" return (luma * 256.0 / 219.0) - 16.0 / 256.0;"
"}\n"
"void main () {\n"
" vec3 yuv;\n"
/* operations translated from videobalanceand tested with glvideomixer
* with one pad's paremeters blend-equation-rgb={subtract,reverse-subtract},
* blend-function-src-rgb=src-color and blend-function-dst-rgb=dst-color */
" float hue_cos = cos (PI * hue);\n"
" float hue_sin = sin (PI * hue);\n"
" vec4 rgba = texture2D (tex, v_texcoord);\n"
" yuv = rgb_to_yuv (rgba.rgb);\n"
" yuv.x = clamp (luma_to_narrow (luma_to_full(yuv.x) * contrast) + brightness, 0.0, 1.0);\n"
" vec2 uv = yuv.yz;\n"
" yuv.y = clamp (0.5 + (((uv.x - 0.5) * hue_cos + (uv.y - 0.5) * hue_sin) * saturation), 0.0, 1.0);\n"
" yuv.z = clamp (0.5 + (((0.5 - uv.x) * hue_sin + (uv.y - 0.5) * hue_cos) * saturation), 0.0, 1.0);\n"
" rgba.rgb = yuv_to_rgb (yuv);\n"
" gl_FragColor = rgba;\n"
"}\n";
/* *INDENT-ON* */
enum
{
PROP_0,
PROP_CONTRAST,
PROP_BRIGHTNESS,
PROP_HUE,
PROP_SATURATION
};
static void gst_gl_color_balance_colorbalance_init (GstColorBalanceInterface *
iface);
static void gst_gl_color_balance_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_color_balance_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
#define gst_gl_color_balance_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstGLColorBalance, gst_gl_color_balance,
GST_TYPE_GL_FILTER,
G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
gst_gl_color_balance_colorbalance_init));
static gboolean
gst_gl_color_balance_is_passthrough (GstGLColorBalance * glcolorbalance)
{
return glcolorbalance->contrast == 1.0 &&
glcolorbalance->brightness == 0.0 &&
glcolorbalance->hue == 0.0 && glcolorbalance->saturation == 1.0;
}
static void
gst_gl_color_balance_update_properties (GstGLColorBalance * glcolorbalance)
{
gboolean current_passthrough, passthrough;
GstBaseTransform *base = GST_BASE_TRANSFORM (glcolorbalance);
GST_OBJECT_LOCK (glcolorbalance);
passthrough = gst_gl_color_balance_is_passthrough (glcolorbalance);
GST_OBJECT_UNLOCK (glcolorbalance);
current_passthrough = gst_base_transform_is_passthrough (base);
gst_base_transform_set_passthrough (base, passthrough);
if (current_passthrough != passthrough)
gst_base_transform_reconfigure_src (base);
}
static gboolean
_create_shader (GstGLColorBalance * balance)
{
GstGLBaseFilter *base_filter = GST_GL_BASE_FILTER (balance);
GstGLFilter *filter = GST_GL_FILTER (balance);
GError *error = NULL;
if (balance->shader)
gst_object_unref (balance->shader);
if (!(balance->shader =
gst_gl_shader_new_link_with_stages (base_filter->context, &error,
gst_glsl_stage_new_default_vertex (base_filter->context),
gst_glsl_stage_new_with_string (base_filter->context,
GL_FRAGMENT_SHADER, GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
color_balance_frag), NULL))) {
GST_ELEMENT_ERROR (balance, RESOURCE, NOT_FOUND, ("%s",
"Failed to initialize colorbalance shader"), ("%s",
error ? error->message : "Unknown error"));
return FALSE;
}
filter->draw_attr_position_loc =
gst_gl_shader_get_attribute_location (balance->shader, "a_position");
filter->draw_attr_texture_loc =
gst_gl_shader_get_attribute_location (balance->shader, "a_texcoord");
return TRUE;
}
static gboolean
gst_gl_color_balance_gl_start (GstGLBaseFilter * base_filter)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (base_filter);
if (!_create_shader (balance))
return FALSE;
return GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter);
}
static void
gst_gl_color_balance_gl_stop (GstGLBaseFilter * base_filter)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (base_filter);
if (balance->shader)
gst_object_unref (balance->shader);
balance->shader = NULL;
GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
}
static void
gst_gl_color_balance_before_transform (GstBaseTransform * base, GstBuffer * buf)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (base);
GstClockTime timestamp, stream_time;
timestamp = GST_BUFFER_TIMESTAMP (buf);
stream_time =
gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
GST_DEBUG_OBJECT (balance, "sync to %" GST_TIME_FORMAT,
GST_TIME_ARGS (timestamp));
if (GST_CLOCK_TIME_IS_VALID (stream_time))
gst_object_sync_values (GST_OBJECT (balance), stream_time);
}
static gboolean
gst_gl_color_balance_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (filter);
if (!balance->shader)
_create_shader (balance);
gst_gl_shader_use (balance->shader);
GST_OBJECT_LOCK (balance);
gst_gl_shader_set_uniform_1f (balance->shader, "brightness",
balance->brightness);
gst_gl_shader_set_uniform_1f (balance->shader, "contrast", balance->contrast);
gst_gl_shader_set_uniform_1f (balance->shader, "saturation",
balance->saturation);
gst_gl_shader_set_uniform_1f (balance->shader, "hue", balance->hue);
GST_OBJECT_UNLOCK (balance);
gst_gl_filter_render_to_target_with_shader (filter, in_tex, out_tex,
balance->shader);
return TRUE;
}
static void
gst_gl_color_balance_finalize (GObject * object)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (object);
GList *channels = NULL;
channels = balance->channels;
while (channels) {
GstColorBalanceChannel *channel = channels->data;
g_object_unref (channel);
channels->data = NULL;
channels = g_list_next (channels);
}
if (balance->channels)
g_list_free (balance->channels);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_gl_color_balance_class_init (GstGLColorBalanceClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
GstGLBaseFilterClass *base_filter_class = (GstGLBaseFilterClass *) klass;
GstGLFilterClass *filter_class = (GstGLFilterClass *) klass;
GST_DEBUG_CATEGORY_INIT (glcolorbalance_debug, "glcolorbalance", 0,
"glcolorbalance");
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
gobject_class->finalize = gst_gl_color_balance_finalize;
gobject_class->set_property = gst_gl_color_balance_set_property;
gobject_class->get_property = gst_gl_color_balance_get_property;
g_object_class_install_property (gobject_class, PROP_CONTRAST,
g_param_spec_double ("contrast", "Contrast", "contrast",
0.0, 2.0, DEFAULT_PROP_CONTRAST,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
g_param_spec_double ("brightness", "Brightness", "brightness", -1.0, 1.0,
DEFAULT_PROP_BRIGHTNESS,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_HUE,
g_param_spec_double ("hue", "Hue", "hue", -1.0, 1.0, DEFAULT_PROP_HUE,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SATURATION,
g_param_spec_double ("saturation", "Saturation", "saturation", 0.0, 2.0,
DEFAULT_PROP_SATURATION,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_static_metadata (gstelement_class, "Video balance",
"Filter/Effect/Video",
"Adjusts brightness, contrast, hue, saturation on a video stream",
"Matthew Waters <matthew@centricular.com>");
trans_class->before_transform =
GST_DEBUG_FUNCPTR (gst_gl_color_balance_before_transform);
trans_class->transform_ip_on_passthrough = FALSE;
base_filter_class->gl_start =
GST_DEBUG_FUNCPTR (gst_gl_color_balance_gl_start);
base_filter_class->gl_stop = GST_DEBUG_FUNCPTR (gst_gl_color_balance_gl_stop);
filter_class->filter_texture =
GST_DEBUG_FUNCPTR (gst_gl_color_balance_filter_texture);
}
static void
gst_gl_color_balance_init (GstGLColorBalance * glcolorbalance)
{
const gchar *channels[4] = { "HUE", "SATURATION",
"BRIGHTNESS", "CONTRAST"
};
gint i;
/* Initialize propertiews */
glcolorbalance->contrast = DEFAULT_PROP_CONTRAST;
glcolorbalance->brightness = DEFAULT_PROP_BRIGHTNESS;
glcolorbalance->hue = DEFAULT_PROP_HUE;
glcolorbalance->saturation = DEFAULT_PROP_SATURATION;
gst_gl_color_balance_update_properties (glcolorbalance);
/* Generate the channels list */
for (i = 0; i < G_N_ELEMENTS (channels); i++) {
GstColorBalanceChannel *channel;
channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
channel->label = g_strdup (channels[i]);
channel->min_value = -1000;
channel->max_value = 1000;
glcolorbalance->channels =
g_list_append (glcolorbalance->channels, channel);
}
}
static const GList *
gst_gl_color_balance_colorbalance_list_channels (GstColorBalance * balance)
{
GstGLColorBalance *glcolorbalance = GST_GL_COLOR_BALANCE (balance);
g_return_val_if_fail (glcolorbalance != NULL, NULL);
g_return_val_if_fail (GST_IS_GL_COLOR_BALANCE (glcolorbalance), NULL);
return glcolorbalance->channels;
}
static void
gst_gl_color_balance_colorbalance_set_value (GstColorBalance * balance,
GstColorBalanceChannel * channel, gint value)
{
GstGLColorBalance *vb = GST_GL_COLOR_BALANCE (balance);
gdouble new_val;
gboolean changed = FALSE;
g_return_if_fail (vb != NULL);
g_return_if_fail (GST_IS_GL_COLOR_BALANCE (vb));
g_return_if_fail (channel->label != NULL);
GST_OBJECT_LOCK (vb);
if (!g_ascii_strcasecmp (channel->label, "HUE")) {
new_val = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
changed = new_val != vb->hue;
vb->hue = new_val;
} else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
new_val = (value + 1000.0) * 2.0 / 2000.0;
changed = new_val != vb->saturation;
vb->saturation = new_val;
} else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
new_val = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
changed = new_val != vb->brightness;
vb->brightness = new_val;
} else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
new_val = (value + 1000.0) * 2.0 / 2000.0;
changed = new_val != vb->contrast;
vb->contrast = new_val;
}
GST_OBJECT_UNLOCK (vb);
if (changed)
gst_gl_color_balance_update_properties (vb);
if (changed) {
gst_color_balance_value_changed (balance, channel,
gst_color_balance_get_value (balance, channel));
}
}
static gint
gst_gl_color_balance_colorbalance_get_value (GstColorBalance * balance,
GstColorBalanceChannel * channel)
{
GstGLColorBalance *vb = GST_GL_COLOR_BALANCE (balance);
gint value = 0;
g_return_val_if_fail (vb != NULL, 0);
g_return_val_if_fail (GST_IS_GL_COLOR_BALANCE (vb), 0);
g_return_val_if_fail (channel->label != NULL, 0);
if (!g_ascii_strcasecmp (channel->label, "HUE")) {
value = (vb->hue + 1) * 2000.0 / 2.0 - 1000.0;
} else if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
value = vb->saturation * 2000.0 / 2.0 - 1000.0;
} else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
value = (vb->brightness + 1) * 2000.0 / 2.0 - 1000.0;
} else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
value = vb->contrast * 2000.0 / 2.0 - 1000.0;
}
return value;
}
static GstColorBalanceType
gst_gl_color_balance_colorbalance_get_balance_type (GstColorBalance * balance)
{
return GST_COLOR_BALANCE_HARDWARE;
}
static void
gst_gl_color_balance_colorbalance_init (GstColorBalanceInterface * iface)
{
iface->list_channels = gst_gl_color_balance_colorbalance_list_channels;
iface->set_value = gst_gl_color_balance_colorbalance_set_value;
iface->get_value = gst_gl_color_balance_colorbalance_get_value;
iface->get_balance_type = gst_gl_color_balance_colorbalance_get_balance_type;
}
static GstColorBalanceChannel *
gst_gl_color_balance_find_channel (GstGLColorBalance * balance,
const gchar * label)
{
GList *l;
for (l = balance->channels; l; l = l->next) {
GstColorBalanceChannel *channel = l->data;
if (g_ascii_strcasecmp (channel->label, label) == 0)
return channel;
}
return NULL;
}
static void
gst_gl_color_balance_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (object);
gdouble d;
const gchar *label = NULL;
GST_OBJECT_LOCK (balance);
switch (prop_id) {
case PROP_CONTRAST:
d = g_value_get_double (value);
GST_DEBUG_OBJECT (balance, "Changing contrast from %lf to %lf",
balance->contrast, d);
if (d != balance->contrast)
label = "CONTRAST";
balance->contrast = d;
break;
case PROP_BRIGHTNESS:
d = g_value_get_double (value);
GST_DEBUG_OBJECT (balance, "Changing brightness from %lf to %lf",
balance->brightness, d);
if (d != balance->brightness)
label = "BRIGHTNESS";
balance->brightness = d;
break;
case PROP_HUE:
d = g_value_get_double (value);
GST_DEBUG_OBJECT (balance, "Changing hue from %lf to %lf", balance->hue,
d);
if (d != balance->hue)
label = "HUE";
balance->hue = d;
break;
case PROP_SATURATION:
d = g_value_get_double (value);
GST_DEBUG_OBJECT (balance, "Changing saturation from %lf to %lf",
balance->saturation, d);
if (d != balance->saturation)
label = "SATURATION";
balance->saturation = d;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_OBJECT_UNLOCK (balance);
gst_gl_color_balance_update_properties (balance);
if (label) {
GstColorBalanceChannel *channel =
gst_gl_color_balance_find_channel (balance, label);
gst_color_balance_value_changed (GST_COLOR_BALANCE (balance), channel,
gst_color_balance_get_value (GST_COLOR_BALANCE (balance), channel));
}
}
static void
gst_gl_color_balance_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLColorBalance *balance = GST_GL_COLOR_BALANCE (object);
switch (prop_id) {
case PROP_CONTRAST:
g_value_set_double (value, balance->contrast);
break;
case PROP_BRIGHTNESS:
g_value_set_double (value, balance->brightness);
break;
case PROP_HUE:
g_value_set_double (value, balance->hue);
break;
case PROP_SATURATION:
g_value_set_double (value, balance->saturation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}

View file

@ -1,73 +0,0 @@
/* 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.
*/
#ifndef __GST_GL_COLOR_BALANCE_H__
#define __GST_GL_COLOR_BALANCE_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_COLOR_BALANCE \
(gst_gl_color_balance_get_type())
#define GST_GL_COLOR_BALANCE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_COLOR_BALANCE,GstGLColorBalance))
#define GST_GL_COLOR_BALANCE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_COLOR_BALANCE,GstGLColorBalanceClass))
#define GST_IS_GL_COLOR_BALANCE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_COLOR_BALANCE))
#define GST_IS_GL_COLOR_BALANCE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_COLOR_BALANCE))
typedef struct _GstGLColorBalance GstGLColorBalance;
typedef struct _GstGLColorBalanceClass GstGLColorBalanceClass;
/**
* GstGLColorBalance:
*
* Opaque data structure.
*/
struct _GstGLColorBalance {
GstGLFilter videofilter;
/* < private > */
GstGLShader *shader;
/* channels for interface */
GList *channels;
/* properties */
gdouble contrast;
gdouble brightness;
gdouble hue;
gdouble saturation;
};
struct _GstGLColorBalanceClass {
GstGLFilterClass parent_class;
};
GType gst_gl_color_balance_get_type(void);
G_END_DECLS
#endif /* __GST_GL_COLOR_BALANCE_H__ */

View file

@ -1,245 +0,0 @@
/*
* GStreamer
* Copyright (C) 2012-2014 Matthew Waters <ystree00@gmail.com>
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gl.h>
#include "gstglcolorconvertelement.h"
GST_DEBUG_CATEGORY_STATIC (gst_gl_color_convert_element_debug);
#define GST_CAT_DEFAULT gst_gl_color_convert_element_debug
G_DEFINE_TYPE_WITH_CODE (GstGLColorConvertElement, gst_gl_color_convert_element,
GST_TYPE_GL_BASE_FILTER,
GST_DEBUG_CATEGORY_INIT (gst_gl_color_convert_element_debug,
"glconvertelement", 0, "convert");
);
static gboolean gst_gl_color_convert_element_set_caps (GstBaseTransform * bt,
GstCaps * in_caps, GstCaps * out_caps);
static GstCaps *gst_gl_color_convert_element_transform_caps (GstBaseTransform *
bt, GstPadDirection direction, GstCaps * caps, GstCaps * filter);
static gboolean gst_gl_color_convert_element_get_unit_size (GstBaseTransform *
trans, GstCaps * caps, gsize * size);
static gboolean
gst_gl_color_convert_element_filter_meta (GstBaseTransform * trans,
GstQuery * query, GType api, const GstStructure * params);
static gboolean gst_gl_color_convert_element_decide_allocation (GstBaseTransform
* trans, GstQuery * query);
static GstFlowReturn
gst_gl_color_convert_element_prepare_output_buffer (GstBaseTransform * bt,
GstBuffer * inbuf, GstBuffer ** outbuf);
static GstFlowReturn gst_gl_color_convert_element_transform (GstBaseTransform *
bt, GstBuffer * inbuf, GstBuffer * outbuf);
static GstCaps *gst_gl_color_convert_element_fixate_caps (GstBaseTransform *
bt, GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
static GstStaticPadTemplate gst_gl_color_convert_element_src_pad_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_GL_COLOR_CONVERT_VIDEO_CAPS));
static GstStaticPadTemplate gst_gl_color_convert_element_sink_pad_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_GL_COLOR_CONVERT_VIDEO_CAPS));
static gboolean
gst_gl_color_convert_element_stop (GstBaseTransform * bt)
{
GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (bt);
if (convert->convert) {
gst_object_unref (convert->convert);
convert->convert = NULL;
}
gst_caps_replace (&convert->in_caps, NULL);
gst_caps_replace (&convert->out_caps, NULL);
return
GST_BASE_TRANSFORM_CLASS (gst_gl_color_convert_element_parent_class)->stop
(bt);
}
static void
gst_gl_color_convert_element_class_init (GstGLColorConvertElementClass * klass)
{
GstBaseTransformClass *bt_class = GST_BASE_TRANSFORM_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
bt_class->transform_caps = gst_gl_color_convert_element_transform_caps;
bt_class->set_caps = gst_gl_color_convert_element_set_caps;
bt_class->get_unit_size = gst_gl_color_convert_element_get_unit_size;
bt_class->filter_meta = gst_gl_color_convert_element_filter_meta;
bt_class->decide_allocation = gst_gl_color_convert_element_decide_allocation;
bt_class->prepare_output_buffer =
gst_gl_color_convert_element_prepare_output_buffer;
bt_class->transform = gst_gl_color_convert_element_transform;
bt_class->stop = gst_gl_color_convert_element_stop;
bt_class->fixate_caps = gst_gl_color_convert_element_fixate_caps;
bt_class->passthrough_on_same_caps = TRUE;
gst_element_class_add_static_pad_template (element_class,
&gst_gl_color_convert_element_src_pad_template);
gst_element_class_add_static_pad_template (element_class,
&gst_gl_color_convert_element_sink_pad_template);
gst_element_class_set_metadata (element_class,
"OpenGL color converter", "Filter/Converter/Video",
"Converts between color spaces using OpenGL shaders",
"Matthew Waters <matthew@centricular.com>");
}
static void
gst_gl_color_convert_element_init (GstGLColorConvertElement * convert)
{
gst_base_transform_set_prefer_passthrough (GST_BASE_TRANSFORM (convert),
TRUE);
}
static gboolean
gst_gl_color_convert_element_set_caps (GstBaseTransform * bt,
GstCaps * in_caps, GstCaps * out_caps)
{
GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (bt);
gst_caps_replace (&convert->in_caps, in_caps);
gst_caps_replace (&convert->out_caps, out_caps);
if (convert->convert)
gst_gl_color_convert_set_caps (convert->convert, in_caps, out_caps);
return TRUE;
}
static GstCaps *
gst_gl_color_convert_element_transform_caps (GstBaseTransform * bt,
GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{
GstGLContext *context = GST_GL_BASE_FILTER (bt)->context;
return gst_gl_color_convert_transform_caps (context, direction, caps, filter);
}
static gboolean
gst_gl_color_convert_element_get_unit_size (GstBaseTransform * trans,
GstCaps * caps, gsize * size)
{
gboolean ret = FALSE;
GstVideoInfo info;
ret = gst_video_info_from_caps (&info, caps);
if (ret)
*size = GST_VIDEO_INFO_SIZE (&info);
return TRUE;
}
static gboolean
gst_gl_color_convert_element_filter_meta (GstBaseTransform * trans,
GstQuery * query, GType api, const GstStructure * params)
{
/* propose all metadata upstream */
return TRUE;
}
static gboolean
gst_gl_color_convert_element_decide_allocation (GstBaseTransform * trans,
GstQuery * query)
{
GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (trans);
GstGLContext *context;
/* get gl context */
if (!GST_BASE_TRANSFORM_CLASS
(gst_gl_color_convert_element_parent_class)->decide_allocation (trans,
query))
return FALSE;
context = GST_GL_BASE_FILTER (trans)->context;
if (!convert->convert)
convert->convert = gst_gl_color_convert_new (context);
if (!gst_gl_color_convert_set_caps (convert->convert, convert->in_caps,
convert->out_caps))
return FALSE;
if (!gst_gl_color_convert_decide_allocation (convert->convert, query))
return FALSE;
return TRUE;
}
static GstFlowReturn
gst_gl_color_convert_element_prepare_output_buffer (GstBaseTransform * bt,
GstBuffer * inbuf, GstBuffer ** outbuf)
{
GstGLColorConvertElement *convert = GST_GL_COLOR_CONVERT_ELEMENT (bt);
GstBaseTransformClass *bclass;
bclass = GST_BASE_TRANSFORM_GET_CLASS (bt);
if (gst_base_transform_is_passthrough (bt)) {
*outbuf = inbuf;
return GST_FLOW_OK;
}
if (!convert->convert)
return GST_FLOW_NOT_NEGOTIATED;
*outbuf = gst_gl_color_convert_perform (convert->convert, inbuf);
if (!*outbuf) {
GST_ELEMENT_ERROR (bt, RESOURCE, NOT_FOUND,
("%s", "Failed to convert video buffer"), (NULL));
return GST_FLOW_ERROR;
}
/* basetransform doesn't unref if they're the same */
if (inbuf == *outbuf)
gst_buffer_unref (*outbuf);
else
bclass->copy_metadata (bt, inbuf, *outbuf);
return GST_FLOW_OK;
}
static GstFlowReturn
gst_gl_color_convert_element_transform (GstBaseTransform * bt,
GstBuffer * inbuf, GstBuffer * outbuf)
{
return GST_FLOW_OK;
}
static GstCaps *
gst_gl_color_convert_element_fixate_caps (GstBaseTransform *
bt, GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
{
GstGLContext *context = GST_GL_BASE_FILTER (bt)->context;
return gst_gl_color_convert_fixate_caps (context, direction, caps, othercaps);
}

View file

@ -1,59 +0,0 @@
/*
* GStreamer
* Copyright (C) 2012 Matthew Waters <ystree00@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_COLOR_CONVERT_ELEMENT_H__
#define __GST_GL_COLOR_CONVERT_ELEMENT_H__
#include <gst/video/video.h>
#include <gst/gstmemory.h>
#include <gst/gl/gstgl_fwd.h>
G_BEGIN_DECLS
GType gst_gl_color_convert_element_get_type (void);
#define GST_TYPE_GL_COLOR_CONVERT_ELEMENT (gst_gl_color_convert_element_get_type())
#define GST_GL_COLOR_CONVERT_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_COLOR_CONVERT_ELEMENT,GstGLColorConvertElement))
#define GST_GL_COLOR_CONVERT_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_DISPLAY,GstGLColorConvertElementClass))
#define GST_IS_GL_COLOR_CONVERT_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_COLOR_CONVERT_ELEMENT))
#define GST_IS_GL_COLOR_CONVERT_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_COLOR_CONVERT_ELEMENT))
#define GST_GL_COLOR_CONVERT_ELEMENT_CAST(obj) ((GstGLColorConvertElement*)(obj))
typedef struct _GstGLColorConvertElement GstGLColorConvertElement;
typedef struct _GstGLColorConvertElementClass GstGLColorConvertElementClass;
typedef struct _GstGLColorConvertElementPrivate GstGLColorConvertElementPrivate;
struct _GstGLColorConvertElement
{
GstGLBaseFilter parent;
GstGLColorConvert *convert;
GstCaps *in_caps;
GstCaps *out_caps;
};
struct _GstGLColorConvertElementClass
{
GstGLBaseFilterClass object_class;
};
G_END_DECLS
#endif /* __GST_GL_COLOR_CONVERT_ELEMENT_H__ */

View file

@ -1,187 +0,0 @@
/*
* 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
* @title: glcolorscale
*
* video frame scaling and colorspace conversion.
*
* ## Scaling and Color space conversion
*
* Equivalent to glupload ! gldownload.
*
* ## Examples
* |[
* gst-launch-1.0 -v videotestsrc ! video/x-raw ! glcolorscale ! ximagesink
* ]| A pipeline to test colorspace conversion.
* FBO is required.
|[
* gst-launch-1.0 -v videotestsrc ! video/x-raw, width=640, height=480, format=AYUV ! glcolorscale ! \
* video/x-raw, width=320, height=240, format=YV12 ! videoconvert ! autovideosink
* ]| A pipeline to test hardware scaling and colorspace conversion.
* FBO and GLSL are required.
*
*/
#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");
#define gst_gl_colorscale_parent_class parent_class
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_gl_start (GstGLBaseFilter * base_filter);
static void gst_gl_colorscale_gl_stop (GstGLBaseFilter * base_filter);
static gboolean gst_gl_colorscale_filter_texture (GstGLFilter * filter,
GstGLMemory * in_tex, GstGLMemory * out_tex);
static void
gst_gl_colorscale_class_init (GstGLColorscaleClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
GstBaseTransformClass *basetransform_class;
GstGLBaseFilterClass *base_filter_class;
GstGLFilterClass *filter_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
basetransform_class = GST_BASE_TRANSFORM_CLASS (klass);
base_filter_class = GST_GL_BASE_FILTER_CLASS (klass);
filter_class = GST_GL_FILTER_CLASS (klass);
gst_gl_filter_add_rgba_pad_templates (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>\n"
"Matthew Waters <matthew@centricular.com>");
basetransform_class->passthrough_on_same_caps = TRUE;
base_filter_class->gl_start = GST_DEBUG_FUNCPTR (gst_gl_colorscale_gl_start);
base_filter_class->gl_stop = GST_DEBUG_FUNCPTR (gst_gl_colorscale_gl_stop);
base_filter_class->supported_gl_api =
GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2;
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_gl_start (GstGLBaseFilter * base_filter)
{
GstGLColorscale *colorscale = GST_GL_COLORSCALE (base_filter);
GstGLFilter *filter = GST_GL_FILTER (base_filter);
GstGLShader *shader;
GError *error = NULL;
if (!(shader = gst_gl_shader_new_default (base_filter->context, &error))) {
GST_ERROR_OBJECT (colorscale, "Failed to initialize shader: %s",
error->message);
gst_object_unref (shader);
return FALSE;
}
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");
colorscale->shader = shader;
return GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter);
}
static void
gst_gl_colorscale_gl_stop (GstGLBaseFilter * base_filter)
{
GstGLColorscale *colorscale = GST_GL_COLORSCALE (base_filter);
if (colorscale->shader) {
gst_object_unref (colorscale->shader);
colorscale->shader = NULL;
}
return GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
}
static gboolean
gst_gl_colorscale_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLColorscale *colorscale = GST_GL_COLORSCALE (filter);
if (gst_gl_context_get_gl_api (GST_GL_BASE_FILTER (filter)->context))
gst_gl_filter_render_to_target_with_shader (filter, in_tex, out_tex,
colorscale->shader);
return TRUE;
}

View file

@ -1,58 +0,0 @@
/*
* 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;
GstGLShader *shader;
};
struct _GstGLColorscaleClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_colorscale_get_type (void);
G_END_DECLS
#endif /* _GST_GLCOLORSCALE_H_ */

View file

@ -1,517 +0,0 @@
/*
* 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
* @title: deinterlace
*
* Deinterlacing using based on fragment shaders.
*
* ## Examples
* |[
* gst-launch-1.0 videotestsrc ! glupload ! gldeinterlace ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglfuncs.h>
#include "gstgldeinterlace.h"
#define GST_CAT_DEFAULT gst_gl_deinterlace_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0,
PROP_METHOD
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_deinterlace_debug, "gldeinterlace", 0, "gldeinterlace element");
#define gst_gl_deinterlace_parent_class parent_class
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 gboolean gst_gl_deinterlace_start (GstBaseTransform * trans);
static gboolean gst_gl_deinterlace_reset (GstBaseTransform * trans);
static gboolean gst_gl_deinterlace_init_fbo (GstGLFilter * filter);
static gboolean gst_gl_deinterlace_filter (GstGLFilter * filter,
GstBuffer * inbuf, GstBuffer * outbuf);
static gboolean gst_gl_deinterlace_filter_texture (GstGLFilter * filter,
GstGLMemory * in_tex, GstGLMemory * out_tex);
static gboolean gst_gl_deinterlace_vfir_callback (GstGLFilter * filter,
GstGLMemory * in_tex, gpointer stuff);
static gboolean gst_gl_deinterlace_greedyh_callback (GstGLFilter * filter,
GstGLMemory * in_tex, gpointer stuff);
/* *INDENT-OFF* */
static const gchar *greedyh_fragment_source =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"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"
"varying vec2 v_texcoord;\n"
"void main () {\n"
" if (int(mod(v_texcoord.y * height, 2.0)) == 0) {\n"
" gl_FragColor = vec4(texture2D(tex_prev, v_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(v_texcoord.x, v_texcoord.y - 1.0 / height);\n"
" texcoord_L3 = vec2(v_texcoord.x, v_texcoord.y + 1.0 / height);\n"
" L1 = texture2D(tex_prev, texcoord_L1).rgb;\n"
" L3 = texture2D(tex_prev, texcoord_L3).rgb;\n"
" if (v_texcoord.x == 1.0 && v_texcoord.y == 1.0) {\n"
" L1_1 = L1;\n"
" L3_1 = L3;\n"
" } else {\n"
" texcoord_L1_1 = vec2(v_texcoord.x + 1.0 / width, v_texcoord.y - 1.0 / height);\n"
" texcoord_L3_1 = vec2(v_texcoord.x + 1.0 / width, v_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(v_texcoord.x + v_texcoord.y)) == 0) {\n"
" L1_a1 = L1;\n"
" L3_a1 = L3;\n"
" } else {\n"
" texcoord_L1_a1 = vec2(v_texcoord.x - 1.0 / width, v_texcoord.y - 1.0 / height);\n"
" texcoord_L3_a1 = vec2(v_texcoord.x - 1.0 / width, v_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, v_texcoord).rgb;\n"
" vec3 LP2 = texture2D(tex_prev, v_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";
const gchar *vfir_fragment_source =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"uniform sampler2D tex;\n"
"uniform float width;\n"
"uniform float height;\n"
"varying vec2 v_texcoord;\n"
"void main()\n"
"{\n"
" vec2 topcoord, botcoord;\n"
" vec4 cur_color, top_color, bot_color;\n"
" topcoord.x = v_texcoord.x;\n"
" botcoord.x = v_texcoord.x;\n"
" if (v_texcoord.y == 0.0 || v_texcoord.y == 1.0) {\n"
" topcoord.y = v_texcoord.y ;\n"
" botcoord.y = v_texcoord.y ;\n"
" }\n"
" else {\n"
" topcoord.y = v_texcoord.y - 1.0/height;\n"
" botcoord.y = v_texcoord.y + 1.0/height;\n"
" }\n"
" cur_color = texture2D(tex, v_texcoord);\n"
" top_color = texture2D(tex, topcoord);\n"
" bot_color = texture2D(tex, botcoord);\n"
" gl_FragColor = 0.5*cur_color + 0.25*top_color + 0.25*bot_color;\n"
"}";
/* *INDENT-ON* */
/* dont' forget to edit the following when a new method is added */
typedef enum
{
GST_GL_DEINTERLACE_VFIR,
GST_GL_DEINTERLACE_GREEDYH
} GstGLDeinterlaceMethod;
static const GEnumValue *
gst_gl_deinterlace_get_methods (void)
{
static const GEnumValue method_types[] = {
{GST_GL_DEINTERLACE_VFIR, "Blur Vertical", "vfir"},
{GST_GL_DEINTERLACE_GREEDYH, "Motion Adaptive: Advanced Detection",
"greedyh"},
{0, NULL, NULL}
};
return method_types;
}
#define GST_TYPE_GL_DEINTERLACE_METHODS (gst_gl_deinterlace_method_get_type ())
static GType
gst_gl_deinterlace_method_get_type (void)
{
static GType gl_deinterlace_method_type = 0;
if (!gl_deinterlace_method_type) {
gl_deinterlace_method_type =
g_enum_register_static ("GstGLDeinterlaceMethod",
gst_gl_deinterlace_get_methods ());
}
return gl_deinterlace_method_type;
}
static void
gst_gl_deinterlace_set_method (GstGLDeinterlace * deinterlace,
guint method_types)
{
switch (method_types) {
case GST_GL_DEINTERLACE_VFIR:
deinterlace->deinterlacefunc = gst_gl_deinterlace_vfir_callback;
deinterlace->current_method = method_types;
break;
case GST_GL_DEINTERLACE_GREEDYH:
deinterlace->deinterlacefunc = gst_gl_deinterlace_greedyh_callback;
deinterlace->current_method = method_types;
break;
default:
g_assert_not_reached ();
break;
}
}
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);
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_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>");
g_object_class_install_property (gobject_class,
PROP_METHOD,
g_param_spec_enum ("method",
"Deinterlace Method",
"Select which deinterlace method apply to GL video texture",
GST_TYPE_GL_DEINTERLACE_METHODS,
GST_GL_DEINTERLACE_VFIR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_deinterlace_start;
GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_deinterlace_reset;
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)->init_fbo = gst_gl_deinterlace_init_fbo;
GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api =
GST_GL_API_OPENGL | GST_GL_API_GLES2 | GST_GL_API_OPENGL3;
}
static void
gst_gl_deinterlace_init (GstGLDeinterlace * filter)
{
filter->shaderstable = NULL;
filter->deinterlacefunc = gst_gl_deinterlace_vfir_callback;
filter->current_method = GST_GL_DEINTERLACE_VFIR;
filter->prev_buffer = NULL;
filter->prev_tex = NULL;
}
static gboolean
gst_gl_deinterlace_start (GstBaseTransform * trans)
{
GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (trans);
deinterlace_filter->shaderstable = g_hash_table_new (g_str_hash, g_str_equal);
return GST_BASE_TRANSFORM_CLASS (parent_class)->start (trans);
}
static void
gst_gl_deinterlace_ghash_func_clean (gpointer key, gpointer value,
gpointer data)
{
GstGLShader *shader = (GstGLShader *) value;
gst_object_unref (shader);
value = NULL;
}
static gboolean
gst_gl_deinterlace_reset (GstBaseTransform * trans)
{
GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (trans);
gst_buffer_replace (&deinterlace_filter->prev_buffer, NULL);
//blocking call, wait the opengl thread has destroyed the shader
if (deinterlace_filter->shaderstable) {
/* release shaders in the gl thread */
g_hash_table_foreach (deinterlace_filter->shaderstable,
gst_gl_deinterlace_ghash_func_clean, deinterlace_filter);
/* clean the htable without calling values destructors
* because shaders have been released in the glthread
* through the foreach func */
g_hash_table_unref (deinterlace_filter->shaderstable);
deinterlace_filter->shaderstable = NULL;
}
return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (trans);
}
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) {
case PROP_METHOD:
gst_gl_deinterlace_set_method (filter, g_value_get_enum (value));
break;
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) {
case PROP_METHOD:
g_value_set_enum (value, filter->current_method);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_deinterlace_init_fbo (GstGLFilter * filter)
{
return TRUE;
}
static gboolean
gst_gl_deinterlace_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);
//blocking call, use a FBO
gst_gl_filter_render_to_target (filter, in_tex, out_tex,
deinterlace_filter->deinterlacefunc, 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);
gst_buffer_replace (&deinterlace_filter->prev_buffer, inbuf);
return TRUE;
}
static GstGLShader *
gst_gl_deinterlace_get_fragment_shader (GstGLFilter * filter,
const gchar * shader_name, const gchar * shader_source)
{
GstGLShader *shader = NULL;
GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);
GstGLContext *context = GST_GL_BASE_FILTER (filter)->context;
shader = g_hash_table_lookup (deinterlace_filter->shaderstable, shader_name);
if (!shader) {
GError *error = NULL;
if (!(shader = gst_gl_shader_new_link_with_stages (context, &error,
gst_glsl_stage_new_default_vertex (context),
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
shader_source), NULL))) {
GST_ELEMENT_ERROR (deinterlace_filter, RESOURCE, NOT_FOUND,
("Failed to initialize %s shader", shader_name), (NULL));
}
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");
}
g_hash_table_insert (deinterlace_filter->shaderstable, (gchar *) shader_name,
shader);
return shader;
}
static gboolean
gst_gl_deinterlace_vfir_callback (GstGLFilter * filter, GstGLMemory * in_tex,
gpointer user_data)
{
GstGLContext *context = GST_GL_BASE_FILTER (filter)->context;
const GstGLFuncs *gl = context->gl_vtable;
GstGLShader *shader;
shader = gst_gl_deinterlace_get_fragment_shader (filter, "vfir",
vfir_fragment_source);
if (!shader)
return FALSE;
#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->BindTexture (GL_TEXTURE_2D, gst_gl_memory_get_texture_id (in_tex));
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gst_gl_shader_set_uniform_1f (shader, "width",
GST_VIDEO_INFO_WIDTH (&filter->out_info));
gst_gl_shader_set_uniform_1f (shader, "height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_filter_draw_fullscreen_quad (filter);
return TRUE;
}
static gboolean
gst_gl_deinterlace_greedyh_callback (GstGLFilter * filter, GstGLMemory * in_tex,
gpointer user_data)
{
GstGLShader *shader;
GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);
GstGLContext *context = GST_GL_BASE_FILTER (filter)->context;
GstGLFuncs *gl = context->gl_vtable;
shader =
gst_gl_deinterlace_get_fragment_shader (filter, "greedhy",
greedyh_fragment_source);
if (!shader)
return FALSE;
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (context)) {
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
}
#endif
gst_gl_shader_use (shader);
if (G_LIKELY (deinterlace_filter->prev_tex != NULL)) {
gl->ActiveTexture (GL_TEXTURE1);
gst_gl_shader_set_uniform_1i (shader, "tex_prev", 1);
gl->BindTexture (GL_TEXTURE_2D,
gst_gl_memory_get_texture_id (deinterlace_filter->prev_tex));
}
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, gst_gl_memory_get_texture_id (in_tex));
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gst_gl_shader_set_uniform_1f (shader, "max_comb", 5.0f / 255.0f);
gst_gl_shader_set_uniform_1f (shader, "motion_threshold", 25.0f / 255.0f);
gst_gl_shader_set_uniform_1f (shader, "motion_sense", 30.0f / 255.0f);
gst_gl_shader_set_uniform_1f (shader, "width",
GST_VIDEO_INFO_WIDTH (&filter->out_info));
gst_gl_shader_set_uniform_1f (shader, "height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_filter_draw_fullscreen_quad (filter);
/* we keep the previous buffer around so this is safe */
deinterlace_filter->prev_tex = in_tex;
return TRUE;
}

View file

@ -1,61 +0,0 @@
/*
* 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))
#define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
typedef struct _GstGLDeinterlace GstGLDeinterlace;
typedef struct _GstGLDeinterlaceClass GstGLDeinterlaceClass;
struct _GstGLDeinterlace
{
GstGLFilter filter;
GstGLFilterRenderFunc deinterlacefunc;
GHashTable *shaderstable;
GstBuffer *prev_buffer;
GstGLMemory * prev_tex;
gint current_method;
};
struct _GstGLDeinterlaceClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_deinterlace_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERLAPLACIAN_H_ */

View file

@ -1,569 +0,0 @@
/*
* 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.
* @title: gldifferencematte.
*
* Saves a background frame and replace it with a pixbuf.
*
* ## Examples
* |[
* gst-launch-1.0 videotestsrc ! glupload ! gldifferencemate location=backgroundimagefile ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <png.h>
#include <gst/gl/gstglfuncs.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");
#define gst_gl_differencematte_parent_class parent_class
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 gboolean gst_gl_differencematte_filter_texture (GstGLFilter * filter,
GstGLMemory * in_tex, GstGLMemory * out_tex);
static gboolean gst_gl_differencematte_loader (GstGLFilter * filter);
enum
{
PROP_0,
PROP_LOCATION,
};
/* init resources that need a gl context */
static gboolean
gst_gl_differencematte_gl_start (GstGLBaseFilter * base_filter)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (base_filter);
GstGLFilter *filter = GST_GL_FILTER (base_filter);
GstGLContext *context = base_filter->context;
GstGLBaseMemoryAllocator *tex_alloc;
GstGLAllocationParams *params;
GError *error = NULL;
gint i;
if (!GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter))
return FALSE;
tex_alloc = (GstGLBaseMemoryAllocator *)
gst_gl_memory_allocator_get_default (context);
params =
(GstGLAllocationParams *) gst_gl_video_allocation_params_new (context,
NULL, &filter->out_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D, GST_GL_RGBA);
for (i = 0; i < 4; i++)
differencematte->midtexture[i] =
(GstGLMemory *) gst_gl_base_memory_alloc (tex_alloc, params);
gst_gl_allocation_params_free (params);
gst_object_unref (tex_alloc);
if (!(differencematte->identity_shader =
gst_gl_shader_new_default (context, &error))) {
GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND, ("%s",
"Failed to compile identity shader"), ("%s", error->message));
return FALSE;
}
if (!(differencematte->shader[0] =
gst_gl_shader_new_link_with_stages (context, &error,
gst_glsl_stage_new_default_vertex (context),
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
difference_fragment_source), NULL))) {
GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND, ("%s",
"Failed to compile difference shader"), ("%s", error->message));
return FALSE;
}
if (!(differencematte->shader[1] =
gst_gl_shader_new_link_with_stages (context, &error,
gst_glsl_stage_new_default_vertex (context),
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
hconv7_fragment_source_gles2), NULL))) {
GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND, ("%s",
"Failed to compile convolution shader"), ("%s", error->message));
return FALSE;
}
if (!(differencematte->shader[2] =
gst_gl_shader_new_link_with_stages (context, &error,
gst_glsl_stage_new_default_vertex (context),
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
vconv7_fragment_source_gles2), NULL))) {
GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND, ("%s",
"Failed to compile convolution shader"), ("%s", error->message));
return FALSE;
}
if (!(differencematte->shader[3] =
gst_gl_shader_new_link_with_stages (context, &error,
gst_glsl_stage_new_default_vertex (context),
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
texture_interp_fragment_source), NULL))) {
GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND, ("%s",
"Failed to compile interpolation shader"), ("%s", error->message));
return FALSE;
}
/* FIXME: this should really be per shader */
filter->draw_attr_position_loc =
gst_gl_shader_get_attribute_location (differencematte->shader[2],
"a_position");
filter->draw_attr_texture_loc =
gst_gl_shader_get_attribute_location (differencematte->shader[2],
"a_texcoord");
return TRUE;
}
/* free resources that need a gl context */
static void
gst_gl_differencematte_gl_stop (GstGLBaseFilter * base_filter)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (base_filter);
gint i;
if (differencematte->savedbgtexture) {
gst_memory_unref (GST_MEMORY_CAST (differencematte->savedbgtexture));
differencematte->savedbgtexture = NULL;
}
if (differencematte->newbgtexture) {
gst_memory_unref (GST_MEMORY_CAST (differencematte->newbgtexture));
differencematte->newbgtexture = NULL;
}
for (i = 0; i < 4; i++) {
if (differencematte->identity_shader) {
gst_object_unref (differencematte->identity_shader);
differencematte->identity_shader = NULL;
}
if (differencematte->shader[i]) {
gst_object_unref (differencematte->shader[i]);
differencematte->shader[i] = NULL;
}
if (differencematte->midtexture[i]) {
gst_memory_unref (GST_MEMORY_CAST (differencematte->midtexture[i]));
differencematte->midtexture[i] = NULL;
}
}
differencematte->location = NULL;
differencematte->pixbuf = NULL;
differencematte->bg_has_changed = FALSE;
GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
}
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);
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
gobject_class->set_property = gst_gl_differencematte_set_property;
gobject_class->get_property = gst_gl_differencematte_get_property;
GST_GL_BASE_FILTER_CLASS (klass)->gl_start = gst_gl_differencematte_gl_start;
GST_GL_BASE_FILTER_CLASS (klass)->gl_stop = gst_gl_differencematte_gl_stop;
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_differencematte_filter_texture;
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>");
GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api =
GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2;
}
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_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (object);
switch (prop_id) {
case PROP_LOCATION:
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
init_pixbuf_texture (GstGLDifferenceMatte * differencematte)
{
GstGLContext *context = GST_GL_BASE_FILTER (differencematte)->context;
GstGLFilter *filter = GST_GL_FILTER (differencematte);
GstGLBaseMemoryAllocator *tex_alloc;
GstGLAllocationParams *params;
GstVideoInfo v_info;
tex_alloc = (GstGLBaseMemoryAllocator *)
gst_gl_memory_allocator_get_default (context);
gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_RGBA,
differencematte->pbuf_width, differencematte->pbuf_height);
params =
(GstGLAllocationParams *) gst_gl_video_allocation_params_new (context,
NULL, &v_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D, GST_GL_RGBA);
differencematte->newbgtexture =
(GstGLMemory *) gst_gl_base_memory_alloc (tex_alloc, params);
gst_gl_allocation_params_free (params);
if (differencematte->savedbgtexture == NULL) {
params =
(GstGLAllocationParams *) gst_gl_video_allocation_params_new (context,
NULL, &filter->out_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D,
GST_GL_RGBA);
differencematte->savedbgtexture =
(GstGLMemory *) gst_gl_base_memory_alloc (tex_alloc, params);
gst_gl_allocation_params_free (params);
}
gst_object_unref (tex_alloc);
}
static gboolean
gst_gl_differencematte_diff (GstGLFilter * filter, GstGLMemory * in_tex,
gpointer stuff)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
const GstGLFuncs *gl = GST_GL_BASE_FILTER (filter)->context->gl_vtable;
gst_gl_shader_use (differencematte->shader[0]);
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, gst_gl_memory_get_texture_id (in_tex));
gst_gl_shader_set_uniform_1i (differencematte->shader[0], "current", 0);
gl->ActiveTexture (GL_TEXTURE1);
gl->BindTexture (GL_TEXTURE_2D,
gst_gl_memory_get_texture_id (differencematte->savedbgtexture));
gst_gl_shader_set_uniform_1i (differencematte->shader[0], "saved", 1);
gst_gl_filter_draw_fullscreen_quad (filter);
return TRUE;
}
static gboolean
gst_gl_differencematte_hblur (GstGLFilter * filter, GstGLMemory * in_tex,
gpointer stuff)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
const GstGLFuncs *gl = GST_GL_BASE_FILTER (filter)->context->gl_vtable;
gst_gl_shader_use (differencematte->shader[1]);
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, gst_gl_memory_get_texture_id (in_tex));
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], "gauss_width",
GST_VIDEO_INFO_WIDTH (&filter->out_info));
gst_gl_filter_draw_fullscreen_quad (filter);
return TRUE;
}
static gboolean
gst_gl_differencematte_vblur (GstGLFilter * filter, GstGLMemory * in_tex,
gpointer stuff)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
const GstGLFuncs *gl = GST_GL_BASE_FILTER (filter)->context->gl_vtable;
gst_gl_shader_use (differencematte->shader[2]);
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, gst_gl_memory_get_texture_id (in_tex));
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], "gauss_height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_filter_draw_fullscreen_quad (filter);
return TRUE;
}
static gboolean
gst_gl_differencematte_interp (GstGLFilter * filter, GstGLMemory * in_tex,
gpointer stuff)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
const GstGLFuncs *gl = GST_GL_BASE_FILTER (filter)->context->gl_vtable;
gst_gl_shader_use (differencematte->shader[3]);
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, gst_gl_memory_get_texture_id (in_tex));
gst_gl_shader_set_uniform_1i (differencematte->shader[3], "blend", 0);
gl->ActiveTexture (GL_TEXTURE1);
gl->BindTexture (GL_TEXTURE_2D, differencematte->newbgtexture->tex_id);
gst_gl_shader_set_uniform_1i (differencematte->shader[3], "base", 1);
gl->ActiveTexture (GL_TEXTURE2);
gl->BindTexture (GL_TEXTURE_2D, differencematte->midtexture[2]->tex_id);
gst_gl_shader_set_uniform_1i (differencematte->shader[3], "alpha", 2);
gst_gl_filter_draw_fullscreen_quad (filter);
return TRUE;
}
static gboolean
gst_gl_differencematte_filter_texture (GstGLFilter * filter,
GstGLMemory * in_tex, GstGLMemory * 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;
init_pixbuf_texture (differencematte);
/* save current frame, needed to calculate difference between
* this frame and next ones */
gst_gl_filter_render_to_target_with_shader (filter, in_tex,
differencematte->savedbgtexture, differencematte->identity_shader);
if (differencematte->pixbuf) {
free (differencematte->pixbuf);
differencematte->pixbuf = NULL;
}
differencematte->bg_has_changed = FALSE;
}
if (differencematte->savedbgtexture != NULL) {
gst_gl_filter_render_to_target (filter, in_tex,
differencematte->midtexture[0], gst_gl_differencematte_diff, NULL);
gst_gl_filter_render_to_target (filter, differencematte->midtexture[0],
differencematte->midtexture[1], gst_gl_differencematte_hblur, NULL);
gst_gl_filter_render_to_target (filter, differencematte->midtexture[1],
differencematte->midtexture[2], gst_gl_differencematte_vblur, NULL);
gst_gl_filter_render_to_target (filter, in_tex, out_tex,
gst_gl_differencematte_interp, NULL);
} else {
gst_gl_filter_render_to_target_with_shader (filter, in_tex, out_tex,
differencematte->identity_shader);
}
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 (!GST_GL_BASE_FILTER (filter)->context)
return TRUE;
if ((fp = fopen (differencematte->location, "rb")) == NULL)
LOAD_ERROR ("file not found");
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose (fp);
LOAD_ERROR ("failed to initialize the png_struct");
}
png_set_error_fn (png_ptr, NULL, NULL, user_warning_fn);
info_ptr = png_create_info_struct (png_ptr);
if (info_ptr == NULL) {
fclose (fp);
png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
LOAD_ERROR ("failed to initialize the memory for image information");
}
png_init_io (png_ptr, fp);
png_set_sig_bytes (png_ptr, sig_read);
png_read_info (png_ptr, info_ptr);
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, int_p_NULL, int_p_NULL);
if (color_type == PNG_COLOR_TYPE_RGB) {
filler = 0xff;
png_set_filler (png_ptr, filler, PNG_FILLER_AFTER);
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
}
if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) {
fclose (fp);
png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
LOAD_ERROR ("color type is not rgb");
}
differencematte->pbuf_width = width;
differencematte->pbuf_height = height;
differencematte->pixbuf =
(guchar *) malloc (sizeof (guchar) * width * height * 4);
rows = (guchar **) malloc (sizeof (guchar *) * height);
for (y = 0; y < height; ++y)
rows[y] = (guchar *) (differencematte->pixbuf + y * width * 4);
png_read_image (png_ptr, rows);
free (rows);
png_read_end (png_ptr, info_ptr);
png_destroy_read_struct (&png_ptr, &info_ptr, png_infopp_NULL);
fclose (fp);
return TRUE;
}

View file

@ -1,62 +0,0 @@
/*
* 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 *identity_shader;
GstGLShader *shader[4];
gchar *location;
gboolean bg_has_changed;
guchar *pixbuf;
gint pbuf_width, pbuf_height;
GstGLMemory *savedbgtexture;
GstGLMemory *newbgtexture;
GstGLMemory *midtexture[4];
GstGLMemory *intexture;
float kernel[7];
};
struct _GstGLDifferenceMatteClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_differencematte_get_type (void);
#endif /* _GST_GL_DIFFERENCEMATTE_H_ */

View file

@ -1,460 +0,0 @@
/*
* GStreamer
* Copyright (C) 2012 Matthew Waters <ystree00@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 <gst/gl/gl.h>
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
#include <gst/gl/egl/gsteglimage.h>
#include <gst/allocators/gstdmabuf.h>
#endif
#include "gstgldownloadelement.h"
GST_DEBUG_CATEGORY_STATIC (gst_gl_download_element_debug);
#define GST_CAT_DEFAULT gst_gl_download_element_debug
#define gst_gl_download_element_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstGLDownloadElement, gst_gl_download_element,
GST_TYPE_GL_BASE_FILTER,
GST_DEBUG_CATEGORY_INIT (gst_gl_download_element_debug, "gldownloadelement",
0, "download element"););
static gboolean gst_gl_download_element_get_unit_size (GstBaseTransform * trans,
GstCaps * caps, gsize * size);
static GstCaps *gst_gl_download_element_transform_caps (GstBaseTransform * bt,
GstPadDirection direction, GstCaps * caps, GstCaps * filter);
static gboolean gst_gl_download_element_set_caps (GstBaseTransform * bt,
GstCaps * in_caps, GstCaps * out_caps);
static GstFlowReturn
gst_gl_download_element_prepare_output_buffer (GstBaseTransform * bt,
GstBuffer * buffer, GstBuffer ** outbuf);
static GstFlowReturn gst_gl_download_element_transform (GstBaseTransform * bt,
GstBuffer * buffer, GstBuffer * outbuf);
static gboolean gst_gl_download_element_decide_allocation (GstBaseTransform *
trans, GstQuery * query);
static void gst_gl_download_element_finalize (GObject * object);
static GstStaticPadTemplate gst_gl_download_element_src_pad_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
"video/x-raw(" GST_CAPS_FEATURE_MEMORY_DMABUF "); "
#endif
"video/x-raw; video/x-raw(memory:GLMemory)"));
static GstStaticPadTemplate gst_gl_download_element_sink_pad_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw(memory:GLMemory); video/x-raw"));
static void
gst_gl_download_element_class_init (GstGLDownloadElementClass * klass)
{
GstBaseTransformClass *bt_class = GST_BASE_TRANSFORM_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
bt_class->transform_caps = gst_gl_download_element_transform_caps;
bt_class->set_caps = gst_gl_download_element_set_caps;
bt_class->get_unit_size = gst_gl_download_element_get_unit_size;
bt_class->prepare_output_buffer =
gst_gl_download_element_prepare_output_buffer;
bt_class->transform = gst_gl_download_element_transform;
bt_class->decide_allocation = gst_gl_download_element_decide_allocation;
bt_class->passthrough_on_same_caps = TRUE;
gst_element_class_add_static_pad_template (element_class,
&gst_gl_download_element_src_pad_template);
gst_element_class_add_static_pad_template (element_class,
&gst_gl_download_element_sink_pad_template);
gst_element_class_set_metadata (element_class,
"OpenGL downloader", "Filter/Video",
"Downloads data from OpenGL", "Matthew Waters <matthew@centricular.com>");
object_class->finalize = gst_gl_download_element_finalize;
}
static void
gst_gl_download_element_init (GstGLDownloadElement * download)
{
gst_base_transform_set_prefer_passthrough (GST_BASE_TRANSFORM (download),
TRUE);
}
static gboolean
gst_gl_download_element_set_caps (GstBaseTransform * bt, GstCaps * in_caps,
GstCaps * out_caps)
{
GstGLDownloadElement *dl = GST_GL_DOWNLOAD_ELEMENT (bt);
GstVideoInfo out_info;
GstCapsFeatures *features = NULL;
if (!gst_video_info_from_caps (&out_info, out_caps))
return FALSE;
features = gst_caps_get_features (out_caps, 0);
dl->do_pbo_transfers = FALSE;
if (dl->dmabuf_allocator) {
gst_object_unref (GST_OBJECT (dl->dmabuf_allocator));
dl->dmabuf_allocator = NULL;
}
if (!features) {
dl->do_pbo_transfers = TRUE;
return TRUE;
}
if (gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) {
/* do nothing with the buffer */
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
} else if (gst_caps_features_contains (features,
GST_CAPS_FEATURE_MEMORY_DMABUF)) {
dl->dmabuf_allocator = gst_dmabuf_allocator_new ();
#endif
} else if (gst_caps_features_contains (features,
GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY)) {
dl->do_pbo_transfers = TRUE;
}
return TRUE;
}
static GstCaps *
_set_caps_features (const GstCaps * caps, const gchar * feature_name)
{
GstCaps *tmp = gst_caps_copy (caps);
guint n = gst_caps_get_size (tmp);
guint i = 0;
for (i = 0; i < n; i++)
gst_caps_set_features (tmp, i,
gst_caps_features_from_string (feature_name));
return tmp;
}
static GstCaps *
gst_gl_download_element_transform_caps (GstBaseTransform * bt,
GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{
GstCaps *result, *tmp;
if (direction == GST_PAD_SRC) {
tmp = _set_caps_features (caps, GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
tmp = gst_caps_merge (gst_caps_ref (caps), tmp);
} else {
GstCaps *newcaps;
tmp = gst_caps_ref (caps);
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
newcaps = _set_caps_features (caps, GST_CAPS_FEATURE_MEMORY_DMABUF);
tmp = gst_caps_merge (tmp, newcaps);
#endif
newcaps = _set_caps_features (caps, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY);
tmp = gst_caps_merge (tmp, newcaps);
}
if (filter) {
result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (tmp);
} else {
result = tmp;
}
GST_DEBUG_OBJECT (bt, "returning caps %" GST_PTR_FORMAT, result);
return result;
}
static gboolean
gst_gl_download_element_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
gsize * size)
{
gboolean ret = FALSE;
GstVideoInfo info;
ret = gst_video_info_from_caps (&info, caps);
if (ret)
*size = GST_VIDEO_INFO_SIZE (&info);
return TRUE;
}
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
struct DmabufInfo
{
GstMemory *dmabuf;
gint stride;
gsize offset;
};
static void
_free_dmabuf_info (struct DmabufInfo *info)
{
gst_memory_unref (info->dmabuf);
g_free (info);
}
static GQuark
_dmabuf_info_quark (void)
{
static GQuark quark = 0;
if (!quark)
quark = g_quark_from_static_string ("GstGLDownloadDmabufInfo");
return quark;
}
static struct DmabufInfo *
_get_cached_dmabuf_info (GstGLMemory * mem)
{
return gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
_dmabuf_info_quark ());
}
static void
_set_cached_dmabuf_info (GstGLMemory * mem, struct DmabufInfo *info)
{
return gst_mini_object_set_qdata (GST_MINI_OBJECT (mem),
_dmabuf_info_quark (), info, (GDestroyNotify) _free_dmabuf_info);
}
struct DmabufTransfer
{
GstGLDownloadElement *download;
GstGLMemory *glmem;
struct DmabufInfo *info;
};
static void
_create_cached_dmabuf_info (GstGLContext * context, gpointer data)
{
struct DmabufTransfer *transfer = (struct DmabufTransfer *) data;
GstEGLImage *image;
image = gst_egl_image_from_texture (context, transfer->glmem, NULL);
if (image) {
int fd;
gint stride;
gsize offset;
if (gst_egl_image_export_dmabuf (image, &fd, &stride, &offset)) {
GstGLDownloadElement *download = transfer->download;
struct DmabufInfo *info;
gsize maxsize;
gst_memory_get_sizes (GST_MEMORY_CAST (transfer->glmem), NULL, &maxsize);
info = g_new0 (struct DmabufInfo, 1);
info->dmabuf =
gst_dmabuf_allocator_alloc (download->dmabuf_allocator, fd, maxsize);
info->stride = stride;
info->offset = offset;
transfer->info = info;
}
gst_egl_image_unref (image);
}
}
static GstBuffer *
_try_export_dmabuf (GstGLDownloadElement * download, GstBuffer * inbuf)
{
GstGLMemory *glmem;
GstBuffer *buffer = NULL;
int i;
gsize offset[GST_VIDEO_MAX_PLANES];
gint stride[GST_VIDEO_MAX_PLANES];
GstCaps *src_caps;
GstVideoInfo out_info;
gsize total_offset;
glmem = GST_GL_MEMORY_CAST (gst_buffer_peek_memory (inbuf, 0));
if (glmem) {
GstGLContext *context = GST_GL_BASE_MEMORY_CAST (glmem)->context;
if (gst_gl_context_get_gl_platform (context) != GST_GL_PLATFORM_EGL)
return NULL;
}
buffer = gst_buffer_new ();
total_offset = 0;
for (i = 0; i < gst_buffer_n_memory (inbuf); i++) {
struct DmabufInfo *info;
glmem = GST_GL_MEMORY_CAST (gst_buffer_peek_memory (inbuf, i));
info = _get_cached_dmabuf_info (glmem);
if (!info) {
GstGLContext *context = GST_GL_BASE_MEMORY_CAST (glmem)->context;
struct DmabufTransfer transfer;
transfer.download = download;
transfer.glmem = glmem;
transfer.info = NULL;
gst_gl_context_thread_add (context, _create_cached_dmabuf_info,
&transfer);
info = transfer.info;
if (info)
_set_cached_dmabuf_info (glmem, info);
}
if (info) {
offset[i] = total_offset + info->offset;
stride[i] = info->stride;
total_offset += gst_memory_get_sizes (info->dmabuf, NULL, NULL);
gst_buffer_insert_memory (buffer, -1, gst_memory_ref (info->dmabuf));
} else {
gst_buffer_unref (buffer);
buffer = NULL;
goto export_complete;
}
}
src_caps = gst_pad_get_current_caps (GST_BASE_TRANSFORM (download)->srcpad);
gst_video_info_from_caps (&out_info, src_caps);
if (download->add_videometa) {
gst_buffer_add_video_meta_full (buffer, GST_VIDEO_FRAME_FLAG_NONE,
out_info.finfo->format, out_info.width, out_info.height,
out_info.finfo->n_planes, offset, stride);
} else {
int i;
gboolean match = TRUE;
for (i = 0; i < gst_buffer_n_memory (inbuf); i++) {
if (offset[i] != out_info.offset[i] || stride[i] != out_info.stride[i]) {
match = FALSE;
break;
}
}
if (!match) {
gst_buffer_unref (buffer);
buffer = NULL;
}
}
export_complete:
return buffer;
}
#endif /* GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF */
static GstFlowReturn
gst_gl_download_element_prepare_output_buffer (GstBaseTransform * bt,
GstBuffer * inbuf, GstBuffer ** outbuf)
{
GstGLDownloadElement *dl = GST_GL_DOWNLOAD_ELEMENT (bt);
gint i, n;
*outbuf = inbuf;
if (dl->do_pbo_transfers) {
n = gst_buffer_n_memory (*outbuf);
for (i = 0; i < n; i++) {
GstMemory *mem = gst_buffer_peek_memory (*outbuf, i);
if (gst_is_gl_memory_pbo (mem))
gst_gl_memory_pbo_download_transfer ((GstGLMemoryPBO *) mem);
}
}
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_DMABUF
else if (dl->dmabuf_allocator) {
GstBuffer *buffer = _try_export_dmabuf (dl, inbuf);
if (buffer) {
if (GST_BASE_TRANSFORM_GET_CLASS (bt)->copy_metadata)
if (!GST_BASE_TRANSFORM_GET_CLASS (bt)->copy_metadata (bt, inbuf,
buffer)) {
GST_ELEMENT_WARNING (GST_ELEMENT (bt), STREAM, NOT_IMPLEMENTED,
("could not copy metadata"), (NULL));
}
*outbuf = buffer;
} else {
GstCaps *src_caps;
GstCapsFeatures *features;
gst_object_unref (dl->dmabuf_allocator);
dl->dmabuf_allocator = NULL;
src_caps = gst_pad_get_current_caps (bt->srcpad);
src_caps = gst_caps_make_writable (src_caps);
features = gst_caps_get_features (src_caps, 0);
gst_caps_features_remove (features, GST_CAPS_FEATURE_MEMORY_DMABUF);
if (!gst_base_transform_update_src_caps (bt, src_caps)) {
GST_ERROR_OBJECT (bt, "DMABuf exportation didn't work and system "
"memory is not supported.");
return GST_FLOW_NOT_NEGOTIATED;
}
}
}
#endif
return GST_FLOW_OK;
}
static GstFlowReturn
gst_gl_download_element_transform (GstBaseTransform * bt,
GstBuffer * inbuf, GstBuffer * outbuf)
{
return GST_FLOW_OK;
}
static gboolean
gst_gl_download_element_decide_allocation (GstBaseTransform * trans,
GstQuery * query)
{
GstGLDownloadElement *download = GST_GL_DOWNLOAD_ELEMENT_CAST (trans);
if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
download->add_videometa = TRUE;
} else {
download->add_videometa = FALSE;
}
return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
query);
}
static void
gst_gl_download_element_finalize (GObject * object)
{
GstGLDownloadElement *download = GST_GL_DOWNLOAD_ELEMENT_CAST (object);
if (download->dmabuf_allocator) {
gst_object_unref (GST_OBJECT (download->dmabuf_allocator));
download->dmabuf_allocator = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}

View file

@ -1,60 +0,0 @@
/*
* GStreamer
* Copyright (C) 2012 Matthew Waters <ystree00@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_DOWNLOAD_ELEMENT_H__
#define __GST_GL_DOWNLOAD_ELEMENT_H__
#include <gst/video/video.h>
#include <gst/gstmemory.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
GType gst_gl_download_element_get_type (void);
#define GST_TYPE_GL_DOWNLOAD_ELEMENT (gst_gl_download_element_get_type())
#define GST_GL_DOWNLOAD_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_DOWNLOAD_ELEMENT,GstGLDownloadElement))
#define GST_GL_DOWNLOAD_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_DISPLAY,GstGLDownloadElementClass))
#define GST_IS_GL_DOWNLOAD_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_DOWNLOAD_ELEMENT))
#define GST_IS_GL_DOWNLOAD_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_DOWNLOAD_ELEMENT))
#define GST_GL_DOWNLOAD_ELEMENT_CAST(obj) ((GstGLDownloadElement*)(obj))
typedef struct _GstGLDownloadElement GstGLDownloadElement;
typedef struct _GstGLDownloadElementClass GstGLDownloadElementClass;
struct _GstGLDownloadElement
{
/* <private> */
GstGLBaseFilter parent;
gboolean do_pbo_transfers;
GstAllocator * dmabuf_allocator;
gboolean add_videometa;
};
struct _GstGLDownloadElementClass
{
/* <private> */
GstGLBaseFilterClass object_class;
};
G_END_DECLS
#endif /* __GST_GL_DOWNLOAD_ELEMENT_H__ */

View file

@ -1,688 +0,0 @@
/*
* 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.
* @title: gleffects.
*
* GL Shading Language effects.
*
* ## Examples
* |[
* gst-launch-1.0 videotestsrc ! glupload ! gleffects effect=5 ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstgleffects.h"
#define GST_CAT_DEFAULT gst_gl_effects_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0 = 0x0,
PROP_EFFECT = 0x1 << 1,
PROP_HSWAP = 0x1 << 2,
PROP_INVERT = 0x1 << 3
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_effects_debug, "gleffects", 0, "gleffects element");
#define gst_gl_effects_parent_class parent_class
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 gboolean gst_gl_effects_init_resources (GstBaseTransform * trans);
static gboolean gst_gl_effects_reset_resources (GstBaseTransform * trans);
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,
GstGLMemory * in_tex, GstGLMemory * out_tex);
static gboolean gst_gl_effects_filters_is_property_supported (const
GstGLEffectsFilterDescriptor *, gint property);
/* 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_EFFECT_SOBEL,
GST_GL_EFFECT_BLUR,
GST_GL_EFFECT_LAPLACIAN,
GST_GL_N_EFFECTS
} GstGLEffectsEffect;
static const GEnumValue *
gst_gl_effects_get_effects (void)
{
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"},
{GST_GL_EFFECT_STRETCH, "Stretch Effect", "stretch"},
{GST_GL_EFFECT_TUNNEL, "Light Tunnel Effect", "tunnel"},
{GST_GL_EFFECT_FISHEYE, "FishEye Effect", "fisheye"},
{GST_GL_EFFECT_TWIRL, "Twirl Effect", "twirl"},
{GST_GL_EFFECT_BULGE, "Bulge Effect", "bulge"},
{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"},
{GST_GL_EFFECT_SOBEL, "Sobel edge detection Effect", "sobel"},
{GST_GL_EFFECT_BLUR, "Blur with 9x9 separable convolution Effect", "blur"},
{GST_GL_EFFECT_LAPLACIAN, "Laplacian Convolution Demo Effect", "laplacian"},
{0, NULL, NULL}
};
return effect_types;
}
#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;
if (!gl_effects_effect_type) {
gl_effects_effect_type =
g_enum_register_static ("GstGLEffectsEffect",
gst_gl_effects_get_effects ());
}
return gl_effects_effect_type;
}
static void
gst_gl_effects_set_effect (GstGLEffects * effects, gint effect_type)
{
GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (effects);
switch (effect_type) {
case GST_GL_EFFECT_IDENTITY:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_identity;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_MIRROR:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_mirror;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_SQUEEZE:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_squeeze;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_STRETCH:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_stretch;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_TUNNEL:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_tunnel;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_FISHEYE:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_fisheye;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_TWIRL:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_twirl;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_BULGE:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_bulge;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_SQUARE:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_square;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_HEAT:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_heat;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_SEPIA:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_sepia;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_XPRO:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_xpro;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_LUMA_XPRO:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_luma_xpro;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_SIN:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_sin;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_XRAY:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_xray;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_GLOW:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_glow;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_SOBEL:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_sobel;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_BLUR:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_blur;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
case GST_GL_EFFECT_LAPLACIAN:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_laplacian;
filter_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
effects->current_effect = effect_type;
break;
default:
g_assert_not_reached ();
}
effects->current_effect = effect_type;
}
/* init resources that need a gl context */
static gboolean
gst_gl_effects_gl_start (GstGLBaseFilter * base_filter)
{
GstGLEffects *effects = GST_GL_EFFECTS (base_filter);
GstGLFilter *filter = GST_GL_FILTER (base_filter);
GstGLContext *context = base_filter->context;
GstGLBaseMemoryAllocator *base_alloc;
GstGLAllocationParams *params;
gint i;
if (!GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter))
return FALSE;
base_alloc = (GstGLBaseMemoryAllocator *)
gst_allocator_find (GST_GL_MEMORY_ALLOCATOR_NAME);
params =
(GstGLAllocationParams *) gst_gl_video_allocation_params_new (context,
NULL, &filter->out_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D, GST_GL_RGBA);
for (i = 0; i < NEEDED_TEXTURES; i++) {
if (effects->midtexture[i])
gst_memory_unref (GST_MEMORY_CAST (effects->midtexture[i]));
effects->midtexture[i] =
(GstGLMemory *) gst_gl_base_memory_alloc (base_alloc, params);
}
gst_object_unref (base_alloc);
gst_gl_allocation_params_free (params);
return TRUE;
}
/* free resources that need a gl context */
static void
gst_gl_effects_gl_stop (GstGLBaseFilter * base_filter)
{
GstGLEffects *effects = GST_GL_EFFECTS (base_filter);
const GstGLFuncs *gl = base_filter->context->gl_vtable;
gint i = 0;
for (i = 0; i < NEEDED_TEXTURES; i++) {
gst_memory_unref (GST_MEMORY_CAST (effects->midtexture[i]));
}
for (i = 0; i < GST_GL_EFFECTS_N_CURVES; i++) {
gl->DeleteTextures (1, &effects->curve[i]);
effects->curve[i] = 0;
}
GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
}
static void
gst_gl_effects_class_init (GstGLEffectsClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_effects_init_resources;
GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_effects_reset_resources;
GST_GL_BASE_FILTER_CLASS (klass)->gl_start = gst_gl_effects_gl_start;
GST_GL_BASE_FILTER_CLASS (klass)->gl_stop = gst_gl_effects_gl_stop;
GST_GL_FILTER_CLASS (klass)->filter_texture = gst_gl_effects_filter_texture;
GST_GL_FILTER_CLASS (klass)->init_fbo = gst_gl_effects_on_init_gl_context;
klass->filter_descriptor = NULL;
gst_element_class_set_metadata (element_class,
"Gstreamer OpenGL Effects", "Filter/Effect/Video",
"GL Shading Language effects",
"Filippo Argiolas <filippo.argiolas@gmail.com>");
GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api =
GST_GL_API_OPENGL | GST_GL_API_GLES2 | GST_GL_API_OPENGL3;
}
static void
gst_gl_effects_filter_class_init (GstGLEffectsClass * klass,
const GstGLEffectsFilterDescriptor * filter_descriptor)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
klass->filter_descriptor = filter_descriptor;
gobject_class->set_property = gst_gl_effects_set_property;
gobject_class->get_property = gst_gl_effects_get_property;
/* if filterDescriptor is null it's a generic gleffects */
if (!filter_descriptor) {
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));
} else {
gchar *description = g_strdup_printf ("GL Shading Language effects - %s",
filter_descriptor->filter_longname);
gst_element_class_set_metadata (element_class,
filter_descriptor->filter_longname, "Filter/Effect/Video",
description, "Filippo Argiolas <filippo.argiolas@gmail.com>");
g_free (description);
}
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));
/* FIXME: make it work on every effect */
if (gst_gl_effects_filters_is_property_supported (filter_descriptor,
PROP_INVERT)) {
g_object_class_install_property (gobject_class, PROP_INVERT,
g_param_spec_boolean ("invert", "Invert the colors for sobel effect",
"Invert colors to get dark edges on bright background when using sobel effect",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
}
static void
set_horizontal_swap (GstGLEffects * effects)
{
#if GST_GL_HAVE_OPENGL
GstGLContext *context = GST_GL_BASE_FILTER (effects)->context;
const 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->horizontal_swap = FALSE;
effects->invert = FALSE;
effects->effect = gst_gl_effects_identity;
}
static void
gst_gl_effects_filter_init (GstGLEffects * effects)
{
gst_gl_effects_set_effect (effects,
GST_GL_EFFECTS_GET_CLASS (effects)->filter_descriptor->effect);
}
static void
gst_gl_effects_ghash_func_clean (gpointer key, gpointer value, gpointer data)
{
GstGLShader *shader = (GstGLShader *) value;
gst_object_unref (shader);
value = NULL;
}
static gboolean
gst_gl_effects_reset_resources (GstBaseTransform * trans)
{
GstGLEffects *effects = GST_GL_EFFECTS (trans);
/* release shaders in the gl thread */
g_hash_table_foreach (effects->shaderstable, gst_gl_effects_ghash_func_clean,
effects);
/* 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;
return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (trans);
}
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;
case PROP_INVERT:
effects->invert = 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;
case PROP_INVERT:
g_value_set_boolean (value, effects->invert);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_effects_init_resources (GstBaseTransform * trans)
{
GstGLEffects *effects = GST_GL_EFFECTS (trans);
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;
}
return GST_BASE_TRANSFORM_CLASS (parent_class)->start (trans);
}
static gboolean
gst_gl_effects_on_init_gl_context (GstGLFilter * filter)
{
return TRUE;
}
static gboolean
gst_gl_effects_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLEffects *effects = GST_GL_EFFECTS (filter);
effects->intexture = in_tex;
effects->outtexture = out_tex;
if (effects->horizontal_swap == TRUE)
set_horizontal_swap (effects);
effects->effect (effects);
return TRUE;
}
GstGLShader *
gst_gl_effects_get_fragment_shader (GstGLEffects * effects,
const gchar * shader_name, const gchar * shader_source_gles2)
{
GstGLShader *shader = NULL;
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = GST_GL_BASE_FILTER (filter)->context;
shader = g_hash_table_lookup (effects->shaderstable, shader_name);
if (!shader) {
GError *error = NULL;
if (!(shader = gst_gl_shader_new_link_with_stages (context, &error,
gst_glsl_stage_new_default_vertex (context),
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
shader_source_gles2), NULL))) {
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("Failed to initialize %s shader", shader_name), (NULL));
}
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");
}
g_hash_table_insert (effects->shaderstable, (gchar *) shader_name, shader);
return shader;
}
static const GstGLEffectsFilterDescriptor *
gst_gl_effects_filters_supported_properties (void)
{
/* Horizontal swap property is supported by all filters */
static const GstGLEffectsFilterDescriptor effects[] = {
{GST_GL_EFFECT_SOBEL, PROP_INVERT, NULL},
{GST_GL_EFFECT_LAPLACIAN, PROP_INVERT, NULL},
{0, 0, NULL}
};
return effects;
}
static inline gboolean
gst_gl_effects_filters_is_property_supported (const GstGLEffectsFilterDescriptor
* descriptor, gint property)
{
/* generic filter (NULL descriptor) supports all properties */
return !descriptor || (descriptor->supported_properties & property);
}
static const GstGLEffectsFilterDescriptor *
gst_gl_effects_filters_descriptors (void)
{
static GstGLEffectsFilterDescriptor *descriptors = NULL;
if (!descriptors) {
const GEnumValue *e;
const GEnumValue *effect = gst_gl_effects_get_effects ();
const GstGLEffectsFilterDescriptor *defined;
guint n_filters = 0, i;
for (e = effect; NULL != e->value_nick; ++e, ++n_filters) {
}
descriptors = g_new0 (GstGLEffectsFilterDescriptor, n_filters + 1);
for (i = 0; i < n_filters; ++i, ++effect) {
descriptors[i].effect = effect->value;
descriptors[i].filter_name = effect->value_nick;
descriptors[i].filter_longname = effect->value_name;
}
for (defined = gst_gl_effects_filters_supported_properties ();
0 != defined->supported_properties; ++defined) {
for (i = 0; i < n_filters; ++i) {
if (descriptors[i].effect == defined->effect) {
descriptors[i].supported_properties = defined->supported_properties;
break;
}
}
if (i >= n_filters) {
GST_WARNING ("Could not match gstgleffects-%s descriptor",
defined->filter_name);
}
}
}
return descriptors;
}
gboolean
gst_gl_effects_register_filters (GstPlugin * plugin, GstRank rank)
{
static volatile gsize registered = 0;
if (g_once_init_enter (&registered)) {
GTypeInfo info = {
sizeof (GstGLEffectsClass),
NULL,
NULL,
(GClassInitFunc) gst_gl_effects_filter_class_init,
NULL,
NULL,
sizeof (GstGLEffects),
0,
NULL
};
GType generic_type =
g_type_register_static (GST_TYPE_GL_EFFECTS, "GstGLEffectsGeneric",
&info, 0);
if (gst_element_register (plugin, "gleffects", rank, generic_type)) {
const GstGLEffectsFilterDescriptor *filters;
for (filters = gst_gl_effects_filters_descriptors ();
NULL != filters->filter_name; ++filters) {
gchar *name = g_strdup_printf ("gleffects_%s", filters->filter_name);
GTypeInfo info = {
sizeof (GstGLEffectsClass),
NULL,
NULL,
(GClassInitFunc) gst_gl_effects_filter_class_init,
NULL,
filters,
sizeof (GstGLEffects),
0,
(GInstanceInitFunc) gst_gl_effects_filter_init
};
GType type =
g_type_register_static (GST_TYPE_GL_EFFECTS, name, &info, 0);
if (!gst_element_register (plugin, name, rank, type)) {
GST_WARNING ("Could not register %s", name);
}
g_free (name);
}
}
g_once_init_leave (&registered, generic_type);
}
return registered;
}

View file

@ -1,119 +0,0 @@
/*
* 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 <gst/gl/gstglfuncs.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))
#define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
#define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
#define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
#define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
#define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
typedef struct _GstGLEffects GstGLEffects;
typedef struct _GstGLEffectsClass GstGLEffectsClass;
typedef struct {
gint effect;
guint supported_properties;
const gchar *filter_name;
const gchar *filter_longname;
} GstGLEffectsFilterDescriptor;
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;
GstGLMemory *intexture;
GstGLMemory *midtexture[NEEDED_TEXTURES];
GstGLMemory *outtexture;
GLuint curve[GST_GL_EFFECTS_N_CURVES];
GHashTable *shaderstable;
gboolean horizontal_swap; /* switch left to right */
gboolean invert; /* colours */
};
struct _GstGLEffectsClass
{
GstGLFilterClass filter_class;
const GstGLEffectsFilterDescriptor *filter_descriptor;
};
GType gst_gl_effects_get_type (void);
gboolean gst_gl_effects_register_filters (GstPlugin *, GstRank);
GstGLShader* gst_gl_effects_get_fragment_shader (GstGLEffects *effects,
const gchar * shader_name, const gchar * shader_source_gles2);
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);
void gst_gl_effects_sobel (GstGLEffects *effects);
void gst_gl_effects_blur (GstGLEffects *effects);
void gst_gl_effects_laplacian (GstGLEffects *effects);
G_END_DECLS
#endif /*__GST_GL_EFFECTS_H__ */

View file

@ -1,229 +0,0 @@
/*
* 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
* @title: glfilterapp
*
* The resize and redraw callbacks can be set from a client code.
*
* ## CLient callbacks
*
* The graphic scene can be written from a client code through the
* two glfilterapp properties.
*
* ## Examples
* see gst-plugins-gl/tests/examples/generic/recordgraphic
*
*/
#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
{
SIGNAL_0,
CLIENT_DRAW_SIGNAL,
LAST_SIGNAL
};
static guint gst_gl_filter_app_signals[LAST_SIGNAL] = { 0 };
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_filter_app_debug, "glfilterapp", 0, "glfilterapp element");
#define gst_gl_filter_app_parent_class parent_class
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,
GstGLMemory * in_tex, GstGLMemory * out_tex);
static gboolean gst_gl_filter_app_gl_start (GstGLBaseFilter * base_filter);
static void gst_gl_filter_app_gl_stop (GstGLBaseFilter * base_filter);
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);
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
gobject_class->set_property = gst_gl_filter_app_set_property;
gobject_class->get_property = gst_gl_filter_app_get_property;
GST_GL_BASE_FILTER_CLASS (klass)->gl_start = gst_gl_filter_app_gl_start;
GST_GL_BASE_FILTER_CLASS (klass)->gl_stop = gst_gl_filter_app_gl_stop;
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;
/**
* GstGLFilterApp::client-draw:
* @object: the #GstGLImageSink
* @texture: the #guint id of the texture.
* @width: the #guint width of the texture.
* @height: the #guint height of the texture.
*
* Will be emitted before to draw the texture. The client should
* redraw the surface/contents with the @texture, @width and @height.
*
* Returns: whether the texture was redrawn by the signal. If not, a
* default redraw will occur.
*/
gst_gl_filter_app_signals[CLIENT_DRAW_SIGNAL] =
g_signal_new ("client-draw", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
G_TYPE_BOOLEAN, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
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>");
GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api =
GST_GL_API_OPENGL | GST_GL_API_GLES2 | GST_GL_API_OPENGL3;
}
static void
gst_gl_filter_app_init (GstGLFilterApp * filter)
{
}
static void
gst_gl_filter_app_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_filter_app_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_filter_app_gl_start (GstGLBaseFilter * base_filter)
{
GstGLFilter *filter = GST_GL_FILTER (base_filter);
GError *error = NULL;
if (!(filter->default_shader =
gst_gl_shader_new_default (base_filter->context, &error))) {
GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND, ("%s",
"Failed to create the default shader"), ("%s", error->message));
return FALSE;
}
return GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter);
}
static void
gst_gl_filter_app_gl_stop (GstGLBaseFilter * base_filter)
{
GstGLFilter *filter = GST_GL_FILTER (base_filter);
if (filter->default_shader)
gst_object_unref (filter->default_shader);
filter->default_shader = NULL;
GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
}
static gboolean
gst_gl_filter_app_set_caps (GstGLFilter * filter, GstCaps * incaps,
GstCaps * outcaps)
{
//GstGLFilterApp* app_filter = GST_GL_FILTER_APP(filter);
return TRUE;
}
struct glcb2
{
GstGLFilterApp *app;
GstGLMemory *in_tex;
GstGLMemory *out_tex;
};
static gboolean
_emit_draw_signal (gpointer data)
{
struct glcb2 *cb = data;
gboolean drawn;
g_signal_emit (cb->app, gst_gl_filter_app_signals[CLIENT_DRAW_SIGNAL], 0,
cb->in_tex->tex_id, gst_gl_memory_get_texture_width (cb->out_tex),
gst_gl_memory_get_texture_height (cb->out_tex), &drawn);
return !drawn;
}
static gboolean
gst_gl_filter_app_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLFilterApp *app_filter = GST_GL_FILTER_APP (filter);
gboolean default_draw;
struct glcb2 cb;
cb.app = app_filter;
cb.in_tex = in_tex;
cb.out_tex = out_tex;
default_draw =
gst_gl_framebuffer_draw_to_texture (filter->fbo,
out_tex, _emit_draw_signal, &cb);
if (default_draw) {
gst_gl_filter_render_to_target_with_shader (filter, in_tex, out_tex,
filter->default_shader);
}
return TRUE;
}

View file

@ -1,51 +0,0 @@
/*
* 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;
};
struct _GstGLFilterAppClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_filter_app_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERAPP_H_ */

View file

@ -1,270 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglfilterbin.h"
#define GST_CAT_DEFAULT gst_gl_filter_bin_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
/* Properties */
enum
{
PROP_0,
PROP_FILTER,
};
enum
{
SIGNAL_0,
SIGNAL_CREATE_ELEMENT,
LAST_SIGNAL
};
static guint gst_gl_filter_bin_signals[LAST_SIGNAL] = { 0 };
#define gst_gl_filter_bin_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstGLFilterBin, gst_gl_filter_bin,
GST_TYPE_BIN, GST_DEBUG_CATEGORY_INIT (gst_gl_filter_bin_debug,
"glfilterbin", 0, "glfilterbin element"););
static void gst_gl_filter_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_filter_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static GstStateChangeReturn gst_gl_filter_bin_change_state (GstElement *
element, GstStateChange transition);
static GstStaticPadTemplate _src_pad_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw(ANY)"));
static void
gst_gl_filter_bin_class_init (GstGLFilterBinClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstCaps *upload_caps;
element_class->change_state = gst_gl_filter_bin_change_state;
gobject_class->set_property = gst_gl_filter_bin_set_property;
gobject_class->get_property = gst_gl_filter_bin_get_property;
gst_element_class_add_static_pad_template (element_class, &_src_pad_template);
upload_caps = gst_gl_upload_get_input_template_caps ();
gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, upload_caps));
gst_caps_unref (upload_caps);
g_object_class_install_property (gobject_class, PROP_FILTER,
g_param_spec_object ("filter",
"GL filter element",
"The GL filter chain to use",
GST_TYPE_ELEMENT,
GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/**
* GstFilterBin::create-element:
* @object: the #GstGLFilterBin
*
* Will be emitted when we need the processing element/s that this bin will use
*
* Returns: a new #GstElement
*/
gst_gl_filter_bin_signals[SIGNAL_CREATE_ELEMENT] =
g_signal_new ("create-element", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
GST_TYPE_ELEMENT, 0);
gst_element_class_set_metadata (element_class,
"GL Filter Bin", "Filter/Video",
"Infrastructure to process GL textures",
"Matthew Waters <matthew@centricular.com>");
}
static void
gst_gl_filter_bin_init (GstGLFilterBin * self)
{
GstPad *pad;
self->upload = gst_element_factory_make ("glupload", NULL);
self->in_convert = gst_element_factory_make ("glcolorconvert", NULL);
self->out_convert = gst_element_factory_make ("glcolorconvert", NULL);
self->download = gst_element_factory_make ("gldownload", NULL);
gst_bin_add (GST_BIN (self), self->upload);
gst_bin_add (GST_BIN (self), self->in_convert);
gst_bin_add (GST_BIN (self), self->out_convert);
gst_bin_add (GST_BIN (self), self->download);
gst_element_link_pads (self->upload, "src", self->in_convert, "sink");
gst_element_link_pads (self->out_convert, "src", self->download, "sink");
pad = gst_element_get_static_pad (self->download, "src");
if (pad) {
GST_DEBUG_OBJECT (self, "setting target src pad %" GST_PTR_FORMAT, pad);
self->srcpad = gst_ghost_pad_new ("src", pad);
gst_element_add_pad (GST_ELEMENT_CAST (self), self->srcpad);
gst_object_unref (pad);
}
pad = gst_element_get_static_pad (self->upload, "sink");
if (pad) {
GST_DEBUG_OBJECT (self, "setting target sink pad %" GST_PTR_FORMAT, pad);
self->sinkpad = gst_ghost_pad_new ("sink", pad);
gst_element_add_pad (GST_ELEMENT_CAST (self), self->sinkpad);
gst_object_unref (pad);
}
}
static gboolean
_connect_filter_element (GstGLFilterBin * self)
{
gboolean res = TRUE;
gst_object_set_name (GST_OBJECT (self->filter), "filter");
res &= gst_bin_add (GST_BIN (self), self->filter);
res &= gst_element_link_pads (self->in_convert, "src", self->filter, "sink");
res &= gst_element_link_pads (self->filter, "src", self->out_convert, "sink");
if (!res)
GST_ERROR_OBJECT (self, "Failed to link filter element into the pipeline");
return res;
}
void
gst_gl_filter_bin_finish_init_with_element (GstGLFilterBin * self,
GstElement * element)
{
g_return_if_fail (GST_IS_ELEMENT (element));
self->filter = element;
if (!_connect_filter_element (self)) {
gst_object_unref (self->filter);
self->filter = NULL;
}
}
void
gst_gl_filter_bin_finish_init (GstGLFilterBin * self)
{
GstGLFilterBinClass *klass = GST_GL_FILTER_BIN_GET_CLASS (self);
GstElement *element = NULL;
if (klass->create_element)
element = klass->create_element ();
if (element)
gst_gl_filter_bin_finish_init_with_element (self, element);
}
static void
gst_gl_filter_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLFilterBin *self = GST_GL_FILTER_BIN (object);
switch (prop_id) {
case PROP_FILTER:
g_value_set_object (value, self->filter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_filter_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLFilterBin *self = GST_GL_FILTER_BIN (object);
switch (prop_id) {
case PROP_FILTER:
{
GstElement *filter = g_value_get_object (value);
if (self->filter)
gst_bin_remove (GST_BIN (self), self->filter);
self->filter = filter;
if (filter) {
gst_object_ref_sink (filter);
_connect_filter_element (self);
}
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstStateChangeReturn
gst_gl_filter_bin_change_state (GstElement * element, GstStateChange transition)
{
GstGLFilterBin *self = GST_GL_FILTER_BIN (element);
GstGLFilterBinClass *klass = GST_GL_FILTER_BIN_GET_CLASS (self);
GstStateChangeReturn ret;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!self->filter) {
if (klass->create_element)
self->filter = klass->create_element ();
if (!self->filter)
g_signal_emit (element,
gst_gl_filter_bin_signals[SIGNAL_CREATE_ELEMENT], 0,
&self->filter);
if (!self->filter) {
GST_ERROR_OBJECT (element, "Failed to retrieve element");
return GST_STATE_CHANGE_FAILURE;
}
if (!_connect_filter_element (self))
return GST_STATE_CHANGE_FAILURE;
}
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
default:
break;
}
return ret;
}

View file

@ -1,80 +0,0 @@
/*
* GStreamer
* Copyright (C) 2007 David 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.
*/
#ifndef _GST_GL_FILTER_BIN_H_
#define _GST_GL_FILTER_BIN_H_
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
GType gst_gl_filter_bin_get_type(void);
#define GST_TYPE_GL_FILTER_BIN (gst_gl_filter_bin_get_type())
#define GST_GL_FILTER_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_BIN,GstGLFilterBin))
#define GST_IS_GL_FILTER_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_BIN))
#define GST_GL_FILTER_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_BIN,GstGLFilterBinClass))
#define GST_IS_GL_FILTER_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_BIN))
#define GST_GL_FILTER_BIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_BIN,GstGLFilterBinClass))
typedef struct _GstGLFilterBin GstGLFilterBin;
typedef struct _GstGLFilterBinClass GstGLFilterBinClass;
/**
* GstGLFilterBin:
* @parent: parent #GstBin
*/
struct _GstGLFilterBin
{
GstBin parent;
GstPad *srcpad;
GstPad *sinkpad;
GstElement *upload;
GstElement *in_convert;
GstElement *filter;
GstElement *out_convert;
GstElement *download;
};
/**
* GstGLFilterBinClass:
* @parent_class: parent class
*/
struct _GstGLFilterBinClass
{
GstBinClass parent_class;
GstElement * (*create_element) (void);
};
void gst_gl_filter_bin_finish_init (GstGLFilterBin * self);
void gst_gl_filter_bin_finish_init_with_element (GstGLFilterBin * self,
GstElement * element);
G_END_DECLS
#endif /* _GST_GL_FILTER_BIN_H_ */

View file

@ -1,496 +0,0 @@
/*
* 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
* @title: glfiltercube
*
* The resize and redraw callbacks can be set from a client code.
*
* ## Examples
* |[
* gst-launch-1.0 -v videotestsrc ! glfiltercube ! glimagesink
* ]| A pipeline to mpa textures on the 6 cube faces..
* FBO is required.
* |[
* gst-launch-1.0 -v videotestsrc ! glfiltercube ! video/x-raw, width=640, height=480 ! glimagesink
* ]| Resize scene after drawing the cube.
* The scene size is greater than the input video size.
|[
* gst-launch-1.0 -v videotestsrc ! video/x-raw, width=640, height=480 ! glfiltercube ! glimagesink
* ]| Resize scene before drawing the cube.
* The scene size is greater than the input video size.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglapi.h>
#include "gstglfiltercube.h"
#include "gstglutils.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");
#define gst_gl_filter_cube_parent_class parent_class
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);
static gboolean gst_gl_filter_cube_gl_start (GstGLBaseFilter * filter);
static void gst_gl_filter_cube_gl_stop (GstGLBaseFilter * filter);
static gboolean _callback (gpointer stuff);
static gboolean gst_gl_filter_cube_filter_texture (GstGLFilter * filter,
GstGLMemory * in_tex, GstGLMemory * out_tex);
/* 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 =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"varying vec2 v_texcoord; \n"
"uniform sampler2D s_texture; \n"
"void main() \n"
"{ \n"
" gl_FragColor = texture2D( s_texture, v_texcoord );\n"
"} \n";
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);
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
gobject_class->set_property = gst_gl_filter_cube_set_property;
gobject_class->get_property = gst_gl_filter_cube_get_property;
GST_GL_BASE_FILTER_CLASS (klass)->gl_start = gst_gl_filter_cube_gl_start;
GST_GL_BASE_FILTER_CLASS (klass)->gl_stop = gst_gl_filter_cube_gl_stop;
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 green 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>");
GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api =
GST_GL_API_OPENGL | GST_GL_API_GLES2 | GST_GL_API_OPENGL3;
}
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;
}
static void
gst_gl_filter_cube_gl_stop (GstGLBaseFilter * base_filter)
{
GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (base_filter);
const GstGLFuncs *gl = base_filter->context->gl_vtable;
if (cube_filter->vao) {
gl->DeleteVertexArrays (1, &cube_filter->vao);
cube_filter->vao = 0;
}
if (cube_filter->vertex_buffer) {
gl->DeleteBuffers (1, &cube_filter->vertex_buffer);
cube_filter->vertex_buffer = 0;
}
if (cube_filter->vbo_indices) {
gl->DeleteBuffers (1, &cube_filter->vbo_indices);
cube_filter->vbo_indices = 0;
}
if (cube_filter->shader) {
gst_object_unref (cube_filter->shader);
cube_filter->shader = NULL;
}
GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
}
static gboolean
gst_gl_filter_cube_gl_start (GstGLBaseFilter * filter)
{
GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
/* blocking call, wait the opengl thread has compiled the shader */
return gst_gl_context_gen_shader (GST_GL_BASE_FILTER (filter)->context,
cube_v_src, cube_f_src, &cube_filter->shader);
}
static gboolean
gst_gl_filter_cube_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
cube_filter->in_tex = in_tex;
return gst_gl_framebuffer_draw_to_texture (filter->fbo, out_tex, _callback,
cube_filter);
}
/* *INDENT-OFF* */
static const GLfloat 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
};
static const 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* */
static void
_bind_buffer (GstGLFilterCube * cube_filter)
{
const GstGLFuncs *gl = GST_GL_BASE_FILTER (cube_filter)->context->gl_vtable;
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, cube_filter->vbo_indices);
gl->BindBuffer (GL_ARRAY_BUFFER, cube_filter->vertex_buffer);
cube_filter->attr_position =
gst_gl_shader_get_attribute_location (cube_filter->shader, "a_position");
cube_filter->attr_texture =
gst_gl_shader_get_attribute_location (cube_filter->shader, "a_texcoord");
/* Load the vertex position */
gl->VertexAttribPointer (cube_filter->attr_position, 3, GL_FLOAT, GL_FALSE,
5 * sizeof (GLfloat), (void *) 0);
/* Load the texture coordinate */
gl->VertexAttribPointer (cube_filter->attr_texture, 2, GL_FLOAT, GL_FALSE,
5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat)));
gl->EnableVertexAttribArray (cube_filter->attr_position);
gl->EnableVertexAttribArray (cube_filter->attr_texture);
}
static void
_unbind_buffer (GstGLFilterCube * cube_filter)
{
const GstGLFuncs *gl = GST_GL_BASE_FILTER (cube_filter)->context->gl_vtable;
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
gl->BindBuffer (GL_ARRAY_BUFFER, 0);
gl->DisableVertexAttribArray (cube_filter->attr_position);
gl->DisableVertexAttribArray (cube_filter->attr_texture);
}
static gboolean
_callback (gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
GstGLFuncs *gl = GST_GL_BASE_FILTER (filter)->context->gl_vtable;
static GLfloat xrot = 0;
static GLfloat yrot = 0;
static GLfloat zrot = 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);
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, cube_filter->in_tex->tex_id);
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);
if (!cube_filter->vertex_buffer) {
if (gl->GenVertexArrays) {
gl->GenVertexArrays (1, &cube_filter->vao);
gl->BindVertexArray (cube_filter->vao);
}
gl->GenBuffers (1, &cube_filter->vertex_buffer);
gl->BindBuffer (GL_ARRAY_BUFFER, cube_filter->vertex_buffer);
gl->BufferData (GL_ARRAY_BUFFER, 6 * 4 * 5 * sizeof (GLfloat), vertices,
GL_STATIC_DRAW);
gl->GenBuffers (1, &cube_filter->vbo_indices);
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, cube_filter->vbo_indices);
gl->BufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indices), indices,
GL_STATIC_DRAW);
if (gl->GenVertexArrays) {
_bind_buffer (cube_filter);
gl->BindVertexArray (0);
}
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
gl->BindBuffer (GL_ARRAY_BUFFER, 0);
}
if (gl->GenVertexArrays)
gl->BindVertexArray (cube_filter->vao);
_bind_buffer (cube_filter);
gl->DrawElements (GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
if (gl->GenVertexArrays)
gl->BindVertexArray (0);
_unbind_buffer (cube_filter);
gl->Disable (GL_DEPTH_TEST);
xrot += 0.3f;
yrot += 0.2f;
zrot += 0.4f;
return TRUE;
}

View file

@ -1,73 +0,0 @@
/*
* 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>
#include <gst/gl/gstglfuncs.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;
GstGLMemory *in_tex;
/* background color */
gfloat red;
gfloat green;
gfloat blue;
/* perspective */
gdouble fovy;
gdouble aspect;
gdouble znear;
gdouble zfar;
GLuint vao;
GLuint vbo_indices;
GLuint vertex_buffer;
GLint attr_position;
GLint attr_texture;
};
struct _GstGLFilterCubeClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_filter_cube_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERCUBE_H_ */

View file

@ -1,412 +0,0 @@
/*
* 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
* @title: glfilterglass
*
* Map textures on moving glass.
*
* ## Examples
* |[
* gst-launch-1.0 -v videotestsrc ! glfilterglass ! glimagesink
* ]| A pipeline inspired from http://www.mdk.org.pl/2007/11/17/gl-colorspace-conversions
* FBO is required.
* |[
* gst-launch-1.0 -v videotestsrc ! glfilterglass ! video/x-raw, width=640, height=480 ! glimagesink
* ]| The scene is greater than the input size.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include <gst/gl/gstglfuncs.h>
#include "gstglfilterglass.h"
#include "gstglutils.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");
#define gst_gl_filter_glass_parent_class parent_class
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 gboolean gst_gl_filter_glass_reset (GstBaseTransform * trans);
static gboolean gst_gl_filter_glass_init_shader (GstGLFilter * filter);
static gboolean gst_gl_filter_glass_filter_texture (GstGLFilter * filter,
GstGLMemory * in_tex, GstGLMemory * 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 gboolean 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);
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_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)->init_fbo = gst_gl_filter_glass_init_shader;
GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_filter_glass_reset;
GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api = GST_GL_API_OPENGL;
}
static void
gst_gl_filter_glass_init (GstGLFilterGlass * filter)
{
filter->shader = NULL;
filter->timestamp = 0;
}
static gboolean
gst_gl_filter_glass_reset (GstBaseTransform * trans)
{
GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (trans);
//blocking call, wait the opengl thread has destroyed the shader
if (glass_filter->shader)
gst_object_unref (glass_filter->shader);
glass_filter->shader = NULL;
if (glass_filter->passthrough_shader)
gst_object_unref (glass_filter->passthrough_shader);
glass_filter->passthrough_shader = NULL;
return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (trans);
}
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 (GST_GL_BASE_FILTER (filter)->context,
glass_vertex_source, glass_fragment_source, &glass_filter->shader);
if (ret)
ret =
gst_gl_context_gen_shader (GST_GL_BASE_FILTER (filter)->context,
passthrough_vertex, passthrough_fragment,
&glass_filter->passthrough_shader);
return ret;
}
static gboolean
gst_gl_filter_glass_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (filter);
glass_filter->in_tex = in_tex;
gst_gl_framebuffer_draw_to_texture (filter->fbo, out_tex,
gst_gl_filter_glass_callback, 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 = GST_GL_BASE_FILTER (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 = GST_GL_BASE_FILTER (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->BindTexture (GL_TEXTURE_2D, texture);
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);
}
static gboolean
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 = GST_GL_BASE_FILTER (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->tex_id;
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 FALSE;
}
}
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 (GST_GL_BASE_FILTER (filter)->context);
gl->Disable (GL_BLEND);
return TRUE;
}

View file

@ -1,57 +0,0 @@
/*
* 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;
GstGLMemory *in_tex;
GstGLMemory *out_tex;
};
struct _GstGLFilterGlassClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_filter_glass_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERGLASS_H_ */

View file

@ -1,556 +0,0 @@
/*
* 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
* @title: glshader
*
* OpenGL fragment shader filter
*
* ## Examples
* |[
* gst-launch-1.0 videotestsrc ! glupload ! glshader fragment="\"`cat myshader.frag`\"" ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
* Depending on the exact OpenGL version chosen and the exact requirements of
* the OpenGL implementation, a #version header may be required.
*
* The following is a simple OpenGL ES (also usable with OpenGL 3 core contexts)
* passthrough shader with the required inputs.
* |[
* #version 100
* #ifdef GL_ES
* precision mediump float;
* #endif
* varying vec2 v_texcoord;
* uniform sampler2D tex;
* uniform float time;
* uniform float width;
* uniform float height;
*
* void main () {
* gl_FragColor = texture2D( tex, v_texcoord );
* }
* ]|
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglfuncs.h>
#include "gstglfiltershader.h"
#if HAVE_GRAPHENE
#include <graphene-gobject.h>
#endif
enum
{
PROP_0,
PROP_SHADER,
PROP_VERTEX,
PROP_FRAGMENT,
PROP_UNIFORMS,
PROP_UPDATE_SHADER,
PROP_LAST,
};
enum
{
SIGNAL_0,
SIGNAL_CREATE_SHADER,
SIGNAL_LAST,
};
static guint gst_gl_shader_signals[SIGNAL_LAST] = { 0 };
#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");
#define gst_gl_filtershader_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstGLFilterShader, gst_gl_filtershader,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_filtershader_finalize (GObject * object);
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 gboolean gst_gl_filtershader_gl_start (GstGLBaseFilter * base);
static void gst_gl_filtershader_gl_stop (GstGLBaseFilter * base);
static gboolean gst_gl_filtershader_filter (GstGLFilter * filter,
GstBuffer * inbuf, GstBuffer * outbuf);
static gboolean gst_gl_filtershader_filter_texture (GstGLFilter * filter,
GstGLMemory * in_tex, GstGLMemory * out_tex);
static gboolean gst_gl_filtershader_hcallback (GstGLFilter * filter,
GstGLMemory * in_tex, gpointer stuff);
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);
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
gobject_class->finalize = gst_gl_filtershader_finalize;
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_SHADER,
g_param_spec_object ("shader", "Shader object",
"GstGLShader to use", GST_TYPE_GL_SHADER,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_VERTEX,
g_param_spec_string ("vertex", "Vertex Source",
"GLSL vertex source", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_FRAGMENT,
g_param_spec_string ("fragment", "Fragment Source",
"GLSL fragment source", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* FIXME: add other stages */
g_object_class_install_property (gobject_class, PROP_UNIFORMS,
g_param_spec_boxed ("uniforms", "GLSL Uniforms",
"GLSL Uniforms", GST_TYPE_STRUCTURE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_UPDATE_SHADER,
g_param_spec_boolean ("update-shader", "Update Shader",
"Emit the \'create-shader\' signal for the next frame",
FALSE, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
/*
* GstGLFilterShader::create-shader:
* @object: the #GstGLFilterShader
*
* Ask's the application for a shader to render with as a result of
* inititialization or setting the 'update-shader' property.
*
* Returns: a new #GstGLShader for use in the rendering pipeline
*/
gst_gl_shader_signals[SIGNAL_CREATE_SHADER] =
g_signal_new ("create-shader", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
GST_TYPE_GL_SHADER, 0);
gst_element_class_set_metadata (element_class,
"OpenGL fragment shader filter", "Filter/Effect",
"Perform operations with a GLSL shader", "<matthew@centricular.com>");
GST_GL_FILTER_CLASS (klass)->filter = gst_gl_filtershader_filter;
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_filtershader_filter_texture;
GST_GL_BASE_FILTER_CLASS (klass)->gl_start = gst_gl_filtershader_gl_start;
GST_GL_BASE_FILTER_CLASS (klass)->gl_stop = gst_gl_filtershader_gl_stop;
GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api =
GST_GL_API_OPENGL | GST_GL_API_GLES2 | GST_GL_API_OPENGL3;
}
static void
gst_gl_filtershader_init (GstGLFilterShader * filtershader)
{
filtershader->new_source = TRUE;
}
static void
gst_gl_filtershader_finalize (GObject * object)
{
GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (object);
g_free (filtershader->vertex);
filtershader->vertex = NULL;
g_free (filtershader->fragment);
filtershader->fragment = NULL;
if (filtershader->uniforms)
gst_structure_free (filtershader->uniforms);
filtershader->uniforms = NULL;
G_OBJECT_CLASS (gst_gl_filtershader_parent_class)->finalize (object);
}
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_SHADER:
GST_OBJECT_LOCK (filtershader);
gst_object_replace ((GstObject **) & filtershader->shader,
g_value_dup_object (value));
filtershader->new_source = FALSE;
GST_OBJECT_UNLOCK (filtershader);
break;
case PROP_VERTEX:
GST_OBJECT_LOCK (filtershader);
g_free (filtershader->vertex);
filtershader->vertex = g_value_dup_string (value);
filtershader->new_source = TRUE;
GST_OBJECT_UNLOCK (filtershader);
break;
case PROP_FRAGMENT:
GST_OBJECT_LOCK (filtershader);
g_free (filtershader->fragment);
filtershader->fragment = g_value_dup_string (value);
filtershader->new_source = TRUE;
GST_OBJECT_UNLOCK (filtershader);
break;
case PROP_UNIFORMS:
GST_OBJECT_LOCK (filtershader);
if (filtershader->uniforms)
gst_structure_free (filtershader->uniforms);
filtershader->uniforms = g_value_dup_boxed (value);
filtershader->new_uniforms = TRUE;
GST_OBJECT_UNLOCK (filtershader);
break;
case PROP_UPDATE_SHADER:
GST_OBJECT_LOCK (filtershader);
filtershader->update_shader = g_value_get_boolean (value);
GST_OBJECT_UNLOCK (filtershader);
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_SHADER:
GST_OBJECT_LOCK (filtershader);
g_value_set_object (value, filtershader->shader);
GST_OBJECT_UNLOCK (filtershader);
break;
case PROP_VERTEX:
GST_OBJECT_LOCK (filtershader);
g_value_set_string (value, filtershader->vertex);
GST_OBJECT_UNLOCK (filtershader);
break;
case PROP_FRAGMENT:
GST_OBJECT_LOCK (filtershader);
g_value_set_string (value, filtershader->fragment);
GST_OBJECT_UNLOCK (filtershader);
break;
case PROP_UNIFORMS:
GST_OBJECT_LOCK (filtershader);
g_value_set_boxed (value, filtershader->uniforms);
GST_OBJECT_UNLOCK (filtershader);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_filtershader_gl_stop (GstGLBaseFilter * base)
{
GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (base);
if (filtershader->shader)
gst_object_unref (filtershader->shader);
filtershader->shader = NULL;
GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base);
}
static gboolean
gst_gl_filtershader_gl_start (GstGLBaseFilter * base)
{
return GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base);
}
static inline gboolean
_gst_clock_time_to_double (GstClockTime time, gdouble * result)
{
if (!GST_CLOCK_TIME_IS_VALID (time))
return FALSE;
*result = (gdouble) time / GST_SECOND;
return TRUE;
}
static inline gboolean
_gint64_time_val_to_double (gint64 time, gdouble * result)
{
if (time == -1)
return FALSE;
*result = (gdouble) time / GST_USECOND;
return TRUE;
}
static gboolean
gst_gl_filtershader_filter (GstGLFilter * filter, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
if (!_gst_clock_time_to_double (GST_BUFFER_PTS (inbuf), &filtershader->time)) {
if (!_gst_clock_time_to_double (GST_BUFFER_DTS (inbuf),
&filtershader->time))
_gint64_time_val_to_double (g_get_monotonic_time (), &filtershader->time);
}
return gst_gl_filter_filter_texture (filter, inbuf, outbuf);
}
static gboolean
gst_gl_filtershader_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
gst_gl_filter_render_to_target (filter, in_tex, out_tex,
gst_gl_filtershader_hcallback, NULL);
if (!filtershader->shader)
return FALSE;
return TRUE;
}
static gboolean
_set_uniform (GQuark field_id, const GValue * value, gpointer user_data)
{
GstGLShader *shader = user_data;
const gchar *field_name = g_quark_to_string (field_id);
if (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_INT)) {
gst_gl_shader_set_uniform_1i (shader, field_name, g_value_get_int (value));
} else if (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_FLOAT)) {
gst_gl_shader_set_uniform_1f (shader, field_name,
g_value_get_float (value));
#if HAVE_GRAPHENE
} else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_VEC2)) {
graphene_vec2_t *vec2 = g_value_get_boxed (value);
float x = graphene_vec2_get_x (vec2);
float y = graphene_vec2_get_y (vec2);
gst_gl_shader_set_uniform_2f (shader, field_name, x, y);
} else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_VEC3)) {
graphene_vec3_t *vec3 = g_value_get_boxed (value);
float x = graphene_vec3_get_x (vec3);
float y = graphene_vec3_get_y (vec3);
float z = graphene_vec3_get_z (vec3);
gst_gl_shader_set_uniform_3f (shader, field_name, x, y, z);
} else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_VEC4)) {
graphene_vec4_t *vec4 = g_value_get_boxed (value);
float x = graphene_vec4_get_x (vec4);
float y = graphene_vec4_get_y (vec4);
float z = graphene_vec4_get_z (vec4);
float w = graphene_vec4_get_w (vec4);
gst_gl_shader_set_uniform_4f (shader, field_name, x, y, z, w);
} else if (G_TYPE_CHECK_VALUE_TYPE ((value), GRAPHENE_TYPE_MATRIX)) {
graphene_matrix_t *matrix = g_value_get_boxed (value);
float matrix_f[16];
graphene_matrix_to_float (matrix, matrix_f);
gst_gl_shader_set_uniform_matrix_4fv (shader, field_name, 1, FALSE,
matrix_f);
#endif
} else {
/* FIXME: Add support for unsigned ints, non 4x4 matrices, etc */
GST_FIXME ("Don't know how to set the \'%s\' paramater. Unknown type",
field_name);
return TRUE;
}
return TRUE;
}
static void
_update_uniforms (GstGLFilterShader * filtershader)
{
if (filtershader->new_uniforms && filtershader->uniforms) {
gst_gl_shader_use (filtershader->shader);
gst_structure_foreach (filtershader->uniforms,
(GstStructureForeachFunc) _set_uniform, filtershader->shader);
filtershader->new_uniforms = FALSE;
}
}
static GstGLShader *
_maybe_recompile_shader (GstGLFilterShader * filtershader)
{
GstGLContext *context = GST_GL_BASE_FILTER (filtershader)->context;
GstGLShader *shader;
GError *error = NULL;
GST_OBJECT_LOCK (filtershader);
if (!filtershader->shader || filtershader->update_shader) {
filtershader->update_shader = FALSE;
GST_OBJECT_UNLOCK (filtershader);
g_signal_emit (filtershader, gst_gl_shader_signals[SIGNAL_CREATE_SHADER], 0,
&shader);
GST_OBJECT_LOCK (filtershader);
if (shader) {
if (filtershader->shader)
gst_object_unref (filtershader->shader);
filtershader->new_source = FALSE;
filtershader->shader = gst_object_ref (shader);
filtershader->new_uniforms = TRUE;
_update_uniforms (filtershader);
GST_OBJECT_UNLOCK (filtershader);
return shader;
}
}
if (filtershader->shader) {
shader = gst_object_ref (filtershader->shader);
_update_uniforms (filtershader);
GST_OBJECT_UNLOCK (filtershader);
return shader;
}
if (filtershader->new_source) {
GstGLSLStage *stage;
shader = gst_gl_shader_new (context);
if (filtershader->vertex) {
if (!(stage = gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_NONE,
filtershader->vertex))) {
g_set_error (&error, GST_GLSL_ERROR, GST_GLSL_ERROR_COMPILE,
"Failed to create shader vertex stage");
goto print_error;
}
} else {
stage = gst_glsl_stage_new_default_vertex (context);
}
if (!gst_gl_shader_compile_attach_stage (shader, stage, &error)) {
gst_object_unref (stage);
goto print_error;
}
if (filtershader->fragment) {
if (!(stage = gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_NONE,
filtershader->fragment))) {
g_set_error (&error, GST_GLSL_ERROR, GST_GLSL_ERROR_COMPILE,
"Failed to create shader fragment stage");
goto print_error;
}
} else {
stage = gst_glsl_stage_new_default_fragment (context);
}
if (!gst_gl_shader_compile_attach_stage (shader, stage, &error)) {
gst_object_unref (stage);
goto print_error;
}
if (!gst_gl_shader_link (shader, &error)) {
goto print_error;
}
if (filtershader->shader)
gst_object_unref (filtershader->shader);
filtershader->shader = gst_object_ref (shader);
filtershader->new_source = FALSE;
filtershader->new_uniforms = TRUE;
_update_uniforms (filtershader);
GST_OBJECT_UNLOCK (filtershader);
return shader;
} else if (filtershader->shader) {
_update_uniforms (filtershader);
shader = gst_object_ref (filtershader->shader);
GST_OBJECT_UNLOCK (filtershader);
return shader;
}
return NULL;
print_error:
if (shader) {
gst_object_unref (shader);
shader = NULL;
}
GST_OBJECT_UNLOCK (filtershader);
GST_ELEMENT_ERROR (filtershader, RESOURCE, NOT_FOUND,
("%s", error->message), (NULL));
return NULL;
}
static gboolean
gst_gl_filtershader_hcallback (GstGLFilter * filter, GstGLMemory * in_tex,
gpointer stuff)
{
GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
GstGLFuncs *gl = GST_GL_BASE_FILTER (filter)->context->gl_vtable;
GstGLShader *shader;
if (!(shader = _maybe_recompile_shader (filtershader)))
return FALSE;
gl->ClearColor (0.0, 0.0, 0.0, 1.0);
gl->Clear (GL_COLOR_BUFFER_BIT);
gst_gl_shader_use (shader);
/* FIXME: propertise these */
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gst_gl_shader_set_uniform_1f (shader, "width",
GST_VIDEO_INFO_WIDTH (&filter->out_info));
gst_gl_shader_set_uniform_1f (shader, "height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gst_gl_shader_set_uniform_1f (shader, "time", filtershader->time);
/* FIXME: propertise these */
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");
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, gst_gl_memory_get_texture_id (in_tex));
gst_gl_filter_draw_fullscreen_quad (filter);
gst_object_unref (shader);
return TRUE;
}

View file

@ -1,63 +0,0 @@
/*
* 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;
/* properties */
GstGLShader *shader;
gchar *vertex;
gchar *fragment;
gboolean update_shader; /* update the shader on the next draw */
GstStructure *uniforms;
gboolean new_source;
gboolean new_uniforms;
gdouble time;
gint attr_position_loc;
gint attr_texture_loc;
};
struct _GstGLFilterShaderClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_filtershader_get_type (void);
#endif /* _GST_GL_FILTERSHADER_H_ */

File diff suppressed because it is too large Load diff

View file

@ -1,157 +0,0 @@
/*
* 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>
#include <gst/gl/gstglfuncs.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 enum
{
GST_GL_ROTATE_METHOD_IDENTITY,
GST_GL_ROTATE_METHOD_90R,
GST_GL_ROTATE_METHOD_180,
GST_GL_ROTATE_METHOD_90L,
GST_GL_ROTATE_METHOD_FLIP_HORIZ,
GST_GL_ROTATE_METHOD_FLIP_VERT,
GST_GL_ROTATE_METHOD_FLIP_UL_LR,
GST_GL_ROTATE_METHOD_FLIP_UR_LL,
GST_GL_ROTATE_METHOD_AUTO,
}GstGLRotateMethod;
typedef struct _GstGLImageSink GstGLImageSink;
typedef struct _GstGLImageSinkClass GstGLImageSinkClass;
struct _GstGLImageSink
{
GstVideoSink video_sink;
guintptr window_id;
guintptr new_window_id;
gulong mouse_sig_id;
gulong key_sig_id;
/* GstVideoOverlay::set_render_rectangle() cache */
gint x;
gint y;
gint width;
gint height;
/* Input info before 3d stereo output conversion, if any */
GstVideoInfo in_info;
GstCaps *in_caps;
/* format/caps we actually hand off to the app */
GstVideoInfo out_info;
GstCaps *out_caps;
GstGLTextureTarget texture_target;
GstGLDisplay *display;
GstGLContext *context;
GstGLContext *other_context;
gboolean handle_events;
gboolean ignore_alpha;
GstGLViewConvert *convert_views;
/* Original input RGBA buffer, ready for display,
* or possible reconversion through the views filter */
GstBuffer *input_buffer;
/* Secondary view buffer - when operating in frame-by-frame mode */
GstBuffer *input_buffer2;
guint next_tex;
GstBuffer *next_buffer;
GstBuffer *next_buffer2; /* frame-by-frame 2nd view */
GstBuffer *next_sync;
GstGLSyncMeta *next_sync_meta;
volatile gint to_quit;
gboolean keep_aspect_ratio;
gint par_n, par_d;
/* avoid replacing the stored_buffer while drawing */
GMutex drawing_lock;
GstBuffer *stored_buffer[2];
GstBuffer *stored_sync;
GstGLSyncMeta *stored_sync_meta;
GLuint redisplay_texture;
/* protected with drawing_lock */
gboolean window_resized;
guint window_width;
guint window_height;
GstVideoRectangle display_rect;
GstGLShader *redisplay_shader;
GLuint vao;
GLuint vbo_indices;
GLuint vertex_buffer;
GLint attr_position;
GLint attr_texture;
GstVideoMultiviewMode mview_output_mode;
GstVideoMultiviewFlags mview_output_flags;
gboolean output_mode_changed;
GstGLStereoDownmix mview_downmix_mode;
GstGLOverlayCompositor *overlay_compositor;
/* current video flip method */
GstGLRotateMethod current_rotate_method;
GstGLRotateMethod rotate_method;
const gfloat *transform_matrix;
};
struct _GstGLImageSinkClass
{
GstVideoSinkClass video_sink_class;
};
GType gst_glimage_sink_get_type(void);
GType gst_gl_image_sink_bin_get_type(void);
G_END_DECLS
#endif

View file

@ -1,832 +0,0 @@
/*
* 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
* @title: gloverlay
*
* Overlay GL video texture with a PNG image
*
* ## Examples
* |[
* gst-launch-1.0 videotestsrc ! gloverlay location=image.jpg ! glimagesink
* ]|
* FBO (Frame Buffer Object) is required.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/base/gsttypefindhelper.h>
#include <gst/gl/gstglconfig.h>
#include "gstgloverlay.h"
#include "effects/gstgleffectssources.h"
#include "gstglutils.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef _MSC_VER
#define HAVE_BOOLEAN
#endif
#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");
#define gst_gl_overlay_parent_class parent_class
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_before_transform (GstBaseTransform * trans,
GstBuffer * outbuf);
static gboolean gst_gl_overlay_filter_texture (GstGLFilter * filter,
GstGLMemory * in_tex, GstGLMemory * out_tex);
static gboolean gst_gl_overlay_load_png (GstGLOverlay * overlay, FILE * fp);
static gboolean gst_gl_overlay_load_jpeg (GstGLOverlay * overlay, FILE * fp);
enum
{
PROP_0,
PROP_LOCATION,
PROP_OFFSET_X,
PROP_OFFSET_Y,
PROP_RELATIVE_X,
PROP_RELATIVE_Y,
PROP_OVERLAY_WIDTH,
PROP_OVERLAY_HEIGHT,
PROP_ALPHA
};
/* *INDENT-OFF* */
/* vertex source */
static const gchar *overlay_v_src =
"attribute vec4 a_position;\n"
"attribute vec2 a_texcoord;\n"
"varying vec2 v_texcoord;\n"
"void main()\n"
"{\n"
" gl_Position = a_position;\n"
" v_texcoord = a_texcoord;\n"
"}";
/* fragment source */
static const gchar *overlay_f_src =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"uniform sampler2D texture;\n"
"uniform float alpha;\n"
"varying vec2 v_texcoord;\n"
"void main()\n"
"{\n"
" vec4 rgba = texture2D( texture, v_texcoord );\n"
" gl_FragColor = vec4(rgba.rgb, rgba.a * alpha);\n"
"}\n";
/* *INDENT-ON* */
/* init resources that need a gl context */
static gboolean
gst_gl_overlay_gl_start (GstGLBaseFilter * base_filter)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (base_filter);
if (!GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter))
return FALSE;
return gst_gl_context_gen_shader (base_filter->context, overlay_v_src,
overlay_f_src, &overlay->shader);
}
/* free resources that need a gl context */
static void
gst_gl_overlay_gl_stop (GstGLBaseFilter * base_filter)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (base_filter);
const GstGLFuncs *gl = base_filter->context->gl_vtable;
if (overlay->shader) {
gst_object_unref (overlay->shader);
overlay->shader = NULL;
}
if (overlay->image_memory) {
gst_memory_unref ((GstMemory *) overlay->image_memory);
overlay->image_memory = NULL;
}
if (overlay->vao) {
gl->DeleteVertexArrays (1, &overlay->vao);
overlay->vao = 0;
}
if (overlay->vbo) {
gl->DeleteBuffers (1, &overlay->vbo);
overlay->vbo = 0;
}
if (overlay->vbo_indices) {
gl->DeleteBuffers (1, &overlay->vbo_indices);
overlay->vbo_indices = 0;
}
if (overlay->overlay_vao) {
gl->DeleteVertexArrays (1, &overlay->overlay_vao);
overlay->overlay_vao = 0;
}
if (overlay->overlay_vbo) {
gl->DeleteBuffers (1, &overlay->overlay_vbo);
overlay->overlay_vbo = 0;
}
GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
}
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);
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
gobject_class->set_property = gst_gl_overlay_set_property;
gobject_class->get_property = gst_gl_overlay_get_property;
GST_GL_BASE_FILTER_CLASS (klass)->gl_start = gst_gl_overlay_gl_start;
GST_GL_BASE_FILTER_CLASS (klass)->gl_stop = gst_gl_overlay_gl_stop;
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_BASE_TRANSFORM_CLASS (klass)->before_transform =
GST_DEBUG_FUNCPTR (gst_gl_overlay_before_transform);
g_object_class_install_property (gobject_class, PROP_LOCATION,
g_param_spec_string ("location", "location",
"Location of image file to overlay", NULL, GST_PARAM_CONTROLLABLE
| GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_OFFSET_X,
g_param_spec_int ("offset-x", "X Offset",
"For positive value, horizontal offset of overlay image in pixels from"
" left of video image. For negative value, horizontal offset of overlay"
" image in pixels from right of video image", G_MININT, G_MAXINT, 0,
GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_OFFSET_Y,
g_param_spec_int ("offset-y", "Y Offset",
"For positive value, vertical offset of overlay image in pixels from"
" top of video image. For negative value, vertical offset of overlay"
" image in pixels from bottom of video image", G_MININT, G_MAXINT, 0,
GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_RELATIVE_X,
g_param_spec_double ("relative-x", "Relative X Offset",
"Horizontal offset of overlay image in fractions of video image "
"width, from top-left corner of video image", 0.0, 1.0, 0.0,
GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_RELATIVE_Y,
g_param_spec_double ("relative-y", "Relative Y Offset",
"Vertical offset of overlay image in fractions of video image "
"height, from top-left corner of video image", 0.0, 1.0, 0.0,
GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_OVERLAY_WIDTH,
g_param_spec_int ("overlay-width", "Overlay Width",
"Width of overlay image in pixels (0 = same as overlay image)", 0,
G_MAXINT, 0,
GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_OVERLAY_HEIGHT,
g_param_spec_int ("overlay-height", "Overlay Height",
"Height of overlay image in pixels (0 = same as overlay image)", 0,
G_MAXINT, 0,
GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ALPHA,
g_param_spec_double ("alpha", "Alpha", "Global alpha of overlay image",
0.0, 1.0, 1.0, GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING
| 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 JPEG/PNG image",
"Filippo Argiolas <filippo.argiolas@gmail.com>, "
"Matthew Waters <matthew@centricular.com>");
GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api =
GST_GL_API_OPENGL | GST_GL_API_GLES2 | GST_GL_API_OPENGL3;
}
static void
gst_gl_overlay_init (GstGLOverlay * overlay)
{
overlay->offset_x = 0;
overlay->offset_y = 0;
overlay->relative_x = 0.0;
overlay->relative_y = 0.0;
overlay->overlay_width = 0;
overlay->overlay_height = 0;
overlay->alpha = 1.0;
}
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:
g_free (overlay->location);
overlay->location_has_changed = TRUE;
overlay->location = g_value_dup_string (value);
break;
case PROP_OFFSET_X:
overlay->offset_x = g_value_get_int (value);
overlay->geometry_change = TRUE;
break;
case PROP_OFFSET_Y:
overlay->offset_y = g_value_get_int (value);
overlay->geometry_change = TRUE;
break;
case PROP_RELATIVE_X:
overlay->relative_x = g_value_get_double (value);
overlay->geometry_change = TRUE;
break;
case PROP_RELATIVE_Y:
overlay->relative_y = g_value_get_double (value);
overlay->geometry_change = TRUE;
break;
case PROP_OVERLAY_WIDTH:
overlay->overlay_width = g_value_get_int (value);
overlay->geometry_change = TRUE;
break;
case PROP_OVERLAY_HEIGHT:
overlay->overlay_height = g_value_get_int (value);
overlay->geometry_change = TRUE;
break;
case PROP_ALPHA:
overlay->alpha = g_value_get_double (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_OFFSET_X:
g_value_set_int (value, overlay->offset_x);
break;
case PROP_OFFSET_Y:
g_value_set_int (value, overlay->offset_y);
break;
case PROP_RELATIVE_X:
g_value_set_double (value, overlay->relative_x);
break;
case PROP_RELATIVE_Y:
g_value_set_double (value, overlay->relative_y);
break;
case PROP_OVERLAY_WIDTH:
g_value_set_int (value, overlay->overlay_width);
break;
case PROP_OVERLAY_HEIGHT:
g_value_set_int (value, overlay->overlay_height);
break;
case PROP_ALPHA:
g_value_set_double (value, overlay->alpha);
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->window_width = width;
overlay->window_height = height;
return TRUE;
}
static void
_unbind_buffer (GstGLOverlay * overlay)
{
GstGLFilter *filter = GST_GL_FILTER (overlay);
const GstGLFuncs *gl = GST_GL_BASE_FILTER (overlay)->context->gl_vtable;
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
gl->BindBuffer (GL_ARRAY_BUFFER, 0);
gl->DisableVertexAttribArray (filter->draw_attr_position_loc);
gl->DisableVertexAttribArray (filter->draw_attr_texture_loc);
}
static void
_bind_buffer (GstGLOverlay * overlay, GLuint vbo)
{
GstGLFilter *filter = GST_GL_FILTER (overlay);
const GstGLFuncs *gl = GST_GL_BASE_FILTER (overlay)->context->gl_vtable;
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, overlay->vbo_indices);
gl->BindBuffer (GL_ARRAY_BUFFER, vbo);
gl->EnableVertexAttribArray (filter->draw_attr_position_loc);
gl->EnableVertexAttribArray (filter->draw_attr_texture_loc);
gl->VertexAttribPointer (filter->draw_attr_position_loc, 3, GL_FLOAT,
GL_FALSE, 5 * sizeof (GLfloat), (void *) 0);
gl->VertexAttribPointer (filter->draw_attr_texture_loc, 2, GL_FLOAT,
GL_FALSE, 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat)));
}
/* *INDENT-OFF* */
float v_vertices[] = {
/*| Vertex | TexCoord |*/
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
};
static const GLushort indices[] = { 0, 1, 2, 0, 2, 3, };
/* *INDENT-ON* */
static gboolean
gst_gl_overlay_callback (GstGLFilter * filter, GstGLMemory * in_tex,
gpointer stuff)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
GstMapInfo map_info;
guint image_tex;
gboolean memory_mapped = FALSE;
const GstGLFuncs *gl = GST_GL_BASE_FILTER (filter)->context->gl_vtable;
gboolean ret = FALSE;
#if GST_GL_HAVE_OPENGL
if (gst_gl_context_get_gl_api (GST_GL_BASE_FILTER (filter)->context) &
GST_GL_API_OPENGL) {
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
}
#endif
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, gst_gl_memory_get_texture_id (in_tex));
gst_gl_shader_use (overlay->shader);
gst_gl_shader_set_uniform_1f (overlay->shader, "alpha", 1.0f);
gst_gl_shader_set_uniform_1i (overlay->shader, "texture", 0);
filter->draw_attr_position_loc =
gst_gl_shader_get_attribute_location (overlay->shader, "a_position");
filter->draw_attr_texture_loc =
gst_gl_shader_get_attribute_location (overlay->shader, "a_texcoord");
gst_gl_filter_draw_fullscreen_quad (filter);
if (!overlay->image_memory)
goto out;
if (!gst_memory_map ((GstMemory *) overlay->image_memory, &map_info,
GST_MAP_READ | GST_MAP_GL) || map_info.data == NULL)
goto out;
memory_mapped = TRUE;
image_tex = *(guint *) map_info.data;
if (!overlay->overlay_vbo) {
if (gl->GenVertexArrays) {
gl->GenVertexArrays (1, &overlay->overlay_vao);
gl->BindVertexArray (overlay->overlay_vao);
}
gl->GenBuffers (1, &overlay->vbo_indices);
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, overlay->vbo_indices);
gl->BufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indices), indices,
GL_STATIC_DRAW);
gl->GenBuffers (1, &overlay->overlay_vbo);
gl->BindBuffer (GL_ARRAY_BUFFER, overlay->overlay_vbo);
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, overlay->vbo_indices);
overlay->geometry_change = TRUE;
}
if (gl->GenVertexArrays) {
gl->BindVertexArray (overlay->overlay_vao);
}
if (overlay->geometry_change) {
gint render_width, render_height;
gfloat x, y, image_width, image_height;
/* *INDENT-OFF* */
float vertices[] = {
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0, 1.0f,
};
/* *INDENT-ON* */
/* scale from [0, 1] -> [-1, 1] */
x = ((gfloat) overlay->offset_x / (gfloat) overlay->window_width +
overlay->relative_x) * 2.0f - 1.0;
y = ((gfloat) overlay->offset_y / (gfloat) overlay->window_height +
overlay->relative_y) * 2.0f - 1.0;
/* scale from [0, 1] -> [0, 2] */
render_width =
overlay->overlay_width >
0 ? overlay->overlay_width : overlay->image_width;
render_height =
overlay->overlay_height >
0 ? overlay->overlay_height : overlay->image_height;
image_width =
((gfloat) render_width / (gfloat) overlay->window_width) * 2.0f;
image_height =
((gfloat) render_height / (gfloat) overlay->window_height) * 2.0f;
vertices[0] = vertices[15] = x;
vertices[5] = vertices[10] = x + image_width;
vertices[1] = vertices[6] = y;
vertices[11] = vertices[16] = y + image_height;
gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), vertices,
GL_STATIC_DRAW);
}
_bind_buffer (overlay, overlay->overlay_vbo);
gl->BindTexture (GL_TEXTURE_2D, image_tex);
gst_gl_shader_set_uniform_1f (overlay->shader, "alpha", overlay->alpha);
gl->Enable (GL_BLEND);
gl->BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl->BlendEquation (GL_FUNC_ADD);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
gl->Disable (GL_BLEND);
ret = TRUE;
out:
if (gl->GenVertexArrays)
gl->BindVertexArray (0);
_unbind_buffer (overlay);
gst_gl_context_clear_shader (GST_GL_BASE_FILTER (filter)->context);
if (memory_mapped)
gst_memory_unmap ((GstMemory *) overlay->image_memory, &map_info);
overlay->geometry_change = FALSE;
return ret;
}
static gboolean
load_file (GstGLOverlay * overlay)
{
FILE *fp;
guint8 buff[16];
gsize n_read;
GstCaps *caps;
GstStructure *structure;
gboolean success = FALSE;
if (overlay->location == NULL)
return TRUE;
if ((fp = fopen (overlay->location, "rb")) == NULL) {
GST_ELEMENT_ERROR (overlay, RESOURCE, NOT_FOUND, ("Can't open file"),
("File: %s", overlay->location));
return FALSE;
}
n_read = fread (buff, 1, sizeof (buff), fp);
if (n_read != sizeof (buff)) {
GST_ELEMENT_ERROR (overlay, STREAM, DECODE, ("Can't read file header"),
("File: %s", overlay->location));
goto out;
}
caps = gst_type_find_helper_for_data (GST_OBJECT (overlay), buff,
sizeof (buff), NULL);
if (caps == NULL) {
GST_ELEMENT_ERROR (overlay, STREAM, DECODE, ("Can't find file type"),
("File: %s", overlay->location));
goto out;
}
fseek (fp, 0, SEEK_SET);
structure = gst_caps_get_structure (caps, 0);
if (gst_structure_has_name (structure, "image/jpeg")) {
success = gst_gl_overlay_load_jpeg (overlay, fp);
} else if (gst_structure_has_name (structure, "image/png")) {
success = gst_gl_overlay_load_png (overlay, fp);
} else {
GST_ELEMENT_ERROR (overlay, STREAM, DECODE, ("Image type not supported"),
("File: %s", overlay->location));
}
out:
fclose (fp);
gst_caps_replace (&caps, NULL);
return success;
}
static gboolean
gst_gl_overlay_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
GstGLMemory * out_tex)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
if (overlay->location_has_changed) {
if (overlay->image_memory) {
gst_memory_unref ((GstMemory *) overlay->image_memory);
overlay->image_memory = NULL;
}
if (!load_file (overlay))
return FALSE;
overlay->location_has_changed = FALSE;
}
gst_gl_filter_render_to_target (filter, in_tex, out_tex,
gst_gl_overlay_callback, overlay);
return TRUE;
}
static void
gst_gl_overlay_before_transform (GstBaseTransform * trans, GstBuffer * outbuf)
{
GstClockTime stream_time;
stream_time = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
GST_BUFFER_TIMESTAMP (outbuf));
if (GST_CLOCK_TIME_IS_VALID (stream_time))
gst_object_sync_values (GST_OBJECT (trans), stream_time);
}
static void
user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
{
g_warning ("%s\n", warning_msg);
}
static gboolean
gst_gl_overlay_load_jpeg (GstGLOverlay * overlay, FILE * fp)
{
GstGLBaseMemoryAllocator *mem_allocator;
GstGLVideoAllocationParams *params;
GstVideoInfo v_info;
GstVideoAlignment v_align;
GstMapInfo map_info;
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW j;
int i;
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->image_width = cinfo.image_width;
overlay->image_height = cinfo.image_height;
if (cinfo.num_components == 1)
gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_Y444,
overlay->image_width, overlay->image_height);
else
gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_RGB,
overlay->image_width, overlay->image_height);
gst_video_alignment_reset (&v_align);
v_align.stride_align[0] = 32 - 1;
gst_video_info_align (&v_info, &v_align);
mem_allocator =
GST_GL_BASE_MEMORY_ALLOCATOR (gst_gl_memory_allocator_get_default
(GST_GL_BASE_FILTER (overlay)->context));
params =
gst_gl_video_allocation_params_new (GST_GL_BASE_FILTER (overlay)->context,
NULL, &v_info, 0, &v_align, GST_GL_TEXTURE_TARGET_2D, GST_GL_RGBA);
overlay->image_memory = (GstGLMemory *)
gst_gl_base_memory_alloc (mem_allocator,
(GstGLAllocationParams *) params);
gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
gst_object_unref (mem_allocator);
if (!gst_memory_map ((GstMemory *) overlay->image_memory, &map_info,
GST_MAP_WRITE)) {
GST_ELEMENT_ERROR (overlay, STREAM, DECODE, ("failed to map memory"),
("File: %s", overlay->location));
return FALSE;
}
for (i = 0; i < overlay->image_height; ++i) {
j = map_info.data + v_info.stride[0] * i;
jpeg_read_scanlines (&cinfo, &j, 1);
}
jpeg_finish_decompress (&cinfo);
jpeg_destroy_decompress (&cinfo);
gst_memory_unmap ((GstMemory *) overlay->image_memory, &map_info);
return TRUE;
}
static gboolean
gst_gl_overlay_load_png (GstGLOverlay * overlay, FILE * fp)
{
GstGLBaseMemoryAllocator *mem_allocator;
GstGLVideoAllocationParams *params;
GstVideoInfo v_info;
GstMapInfo map_info;
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;
guint y = 0;
guchar **rows = NULL;
gint filler;
png_byte magic[8];
gint n_read;
if (!GST_GL_BASE_FILTER (overlay)->context)
return FALSE;
/* Read magic number */
n_read = fread (magic, 1, sizeof (magic), fp);
if (n_read != sizeof (magic)) {
GST_ELEMENT_ERROR (overlay, STREAM, DECODE,
("can't read PNG magic number"), ("File: %s", overlay->location));
return FALSE;
}
/* Check for valid magic number */
if (png_sig_cmp (magic, 0, sizeof (magic))) {
GST_ELEMENT_ERROR (overlay, STREAM, DECODE,
("not a valid PNG image"), ("File: %s", overlay->location));
return FALSE;
}
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
GST_ELEMENT_ERROR (overlay, STREAM, DECODE,
("failed to initialize the png_struct"), ("File: %s",
overlay->location));
return FALSE;
}
png_set_error_fn (png_ptr, NULL, NULL, user_warning_fn);
info_ptr = png_create_info_struct (png_ptr);
if (info_ptr == NULL) {
png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
GST_ELEMENT_ERROR (overlay, STREAM, DECODE,
("failed to initialize the memory for image information"),
("File: %s", overlay->location));
return FALSE;
}
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) {
png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
GST_ELEMENT_ERROR (overlay, STREAM, DECODE,
("color type is not rgb"), ("File: %s", overlay->location));
return FALSE;
}
overlay->image_width = width;
overlay->image_height = height;
gst_video_info_set_format (&v_info, GST_VIDEO_FORMAT_RGBA, width, height);
mem_allocator =
GST_GL_BASE_MEMORY_ALLOCATOR (gst_gl_memory_allocator_get_default
(GST_GL_BASE_FILTER (overlay)->context));
params =
gst_gl_video_allocation_params_new (GST_GL_BASE_FILTER (overlay)->context,
NULL, &v_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D, GST_GL_RGBA);
overlay->image_memory = (GstGLMemory *)
gst_gl_base_memory_alloc (mem_allocator,
(GstGLAllocationParams *) params);
gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
gst_object_unref (mem_allocator);
if (!gst_memory_map ((GstMemory *) overlay->image_memory, &map_info,
GST_MAP_WRITE)) {
png_destroy_read_struct (&png_ptr, &info_ptr, png_infopp_NULL);
GST_ELEMENT_ERROR (overlay, STREAM, DECODE,
("failed to map memory"), ("File: %s", overlay->location));
return FALSE;
}
rows = (guchar **) malloc (sizeof (guchar *) * height);
for (y = 0; y < height; ++y)
rows[y] = (guchar *) (map_info.data + y * width * 4);
png_read_image (png_ptr, rows);
free (rows);
gst_memory_unmap ((GstMemory *) overlay->image_memory, &map_info);
png_read_end (png_ptr, info_ptr);
png_destroy_read_struct (&png_ptr, &info_ptr, png_infopp_NULL);
return TRUE;
}

View file

@ -1,84 +0,0 @@
/*
* 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>
#include <gst/gl/gstglfuncs.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;
/* properties */
gchar *location;
gint offset_x;
gint offset_y;
gdouble relative_x;
gdouble relative_y;
gint overlay_width;
gint overlay_height;
gdouble alpha;
/* <private> */
GstGLShader *shader;
GstGLMemory *image_memory;
gboolean location_has_changed;
gint window_width, window_height;
gint image_width, image_height;
gboolean geometry_change;
GLuint vao;
GLuint overlay_vao;
GLuint vbo;
GLuint overlay_vbo;
GLuint vbo_indices;
GLuint attr_position;
GLuint attr_texture;
};
struct _GstGLOverlayClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_overlay_get_type (void);
G_END_DECLS
#endif /* _GST_GL_OVERLAY_H_ */

View file

@ -1,599 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/video/videooverlay.h>
#include <gst/video/navigation.h>
#include <gst/controller/gstproxycontrolbinding.h>
#include "gstglsinkbin.h"
GST_DEBUG_CATEGORY (gst_debug_gl_sink_bin);
#define GST_CAT_DEFAULT gst_debug_gl_sink_bin
static void gst_gl_sink_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * param_spec);
static void gst_gl_sink_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * param_spec);
static GstStateChangeReturn gst_gl_sink_bin_change_state (GstElement * element,
GstStateChange transition);
static void gst_gl_sink_bin_video_overlay_init (gpointer g_iface,
gpointer g_iface_data);
static void gst_gl_sink_bin_navigation_interface_init (gpointer g_iface,
gpointer g_iface_data);
static void gst_gl_sink_bin_color_balance_init (gpointer g_iface,
gpointer g_iface_data);
#define DEFAULT_SYNC TRUE
#define DEFAULT_MAX_LATENESS -1
#define DEFAULT_QOS FALSE
#define DEFAULT_ASYNC TRUE
#define DEFAULT_TS_OFFSET 0
#define DEFAULT_BLOCKSIZE 4096
#define DEFAULT_RENDER_DELAY 0
#define DEFAULT_ENABLE_LAST_SAMPLE TRUE
#define DEFAULT_THROTTLE_TIME 0
#define DEFAULT_MAX_BITRATE 0
/* GstGLColorBalance properties */
#define DEFAULT_PROP_CONTRAST 1.0
#define DEFAULT_PROP_BRIGHTNESS 0.0
#define DEFAULT_PROP_HUE 0.0
#define DEFAULT_PROP_SATURATION 1.0
enum
{
PROP_0,
PROP_FORCE_ASPECT_RATIO,
PROP_SINK,
PROP_SYNC,
PROP_MAX_LATENESS,
PROP_QOS,
PROP_ASYNC,
PROP_TS_OFFSET,
PROP_ENABLE_LAST_SAMPLE,
PROP_LAST_SAMPLE,
PROP_BLOCKSIZE,
PROP_RENDER_DELAY,
PROP_THROTTLE_TIME,
PROP_MAX_BITRATE,
PROP_CONTRAST,
PROP_BRIGHTNESS,
PROP_HUE,
PROP_SATURATION,
};
enum
{
SIGNAL_0,
SIGNAL_CREATE_ELEMENT,
SIGNAL_LAST,
};
static guint gst_gl_sink_bin_signals[SIGNAL_LAST] = { 0, };
#define gst_gl_sink_bin_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstGLSinkBin, gst_gl_sink_bin,
GST_TYPE_BIN, G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
gst_gl_sink_bin_video_overlay_init);
G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
gst_gl_sink_bin_navigation_interface_init);
G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
gst_gl_sink_bin_color_balance_init)
GST_DEBUG_CATEGORY_INIT (gst_debug_gl_sink_bin, "glimagesink", 0,
"OpenGL Video Sink Bin"));
static void
gst_gl_sink_bin_class_init (GstGLSinkBinClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
GstCaps *upload_caps;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
element_class->change_state = gst_gl_sink_bin_change_state;
gobject_class->set_property = gst_gl_sink_bin_set_property;
gobject_class->get_property = gst_gl_sink_bin_get_property;
g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
g_param_spec_boolean ("force-aspect-ratio",
"Force aspect ratio",
"When enabled, scaling will respect original aspect ratio", TRUE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SINK,
g_param_spec_object ("sink",
"GL sink element",
"The GL sink chain to use",
GST_TYPE_ELEMENT,
GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/* base sink */
g_object_class_install_property (gobject_class, PROP_SYNC,
g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_MAX_LATENESS,
g_param_spec_int64 ("max-lateness", "Max Lateness",
"Maximum number of nanoseconds that a buffer can be late before it "
"is dropped (-1 unlimited)", -1, G_MAXINT64, DEFAULT_MAX_LATENESS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_QOS,
g_param_spec_boolean ("qos", "Qos",
"Generate Quality-of-Service events upstream", DEFAULT_QOS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ASYNC,
g_param_spec_boolean ("async", "Async",
"Go asynchronously to PAUSED", DEFAULT_ASYNC,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
g_param_spec_int64 ("ts-offset", "TS Offset",
"Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ENABLE_LAST_SAMPLE,
g_param_spec_boolean ("enable-last-sample", "Enable Last Buffer",
"Enable the last-sample property", DEFAULT_ENABLE_LAST_SAMPLE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_LAST_SAMPLE,
g_param_spec_boxed ("last-sample", "Last Sample",
"The last sample received in the sink", GST_TYPE_SAMPLE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BLOCKSIZE,
g_param_spec_uint ("blocksize", "Block size",
"Size in bytes to pull per buffer (0 = default)", 0, G_MAXUINT,
DEFAULT_BLOCKSIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_RENDER_DELAY,
g_param_spec_uint64 ("render-delay", "Render Delay",
"Additional render delay of the sink in nanoseconds", 0, G_MAXUINT64,
DEFAULT_RENDER_DELAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_THROTTLE_TIME,
g_param_spec_uint64 ("throttle-time", "Throttle time",
"The time to keep between rendered buffers (0 = disabled)", 0,
G_MAXUINT64, DEFAULT_THROTTLE_TIME,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
g_param_spec_uint64 ("max-bitrate", "Max Bitrate",
"The maximum bits per second to render (0 = disabled)", 0,
G_MAXUINT64, DEFAULT_MAX_BITRATE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* colorbalance */
g_object_class_install_property (gobject_class, PROP_CONTRAST,
g_param_spec_double ("contrast", "Contrast", "contrast",
0.0, 2.0, DEFAULT_PROP_CONTRAST,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
g_param_spec_double ("brightness", "Brightness", "brightness", -1.0, 1.0,
DEFAULT_PROP_BRIGHTNESS,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_HUE,
g_param_spec_double ("hue", "Hue", "hue", -1.0, 1.0, DEFAULT_PROP_HUE,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SATURATION,
g_param_spec_double ("saturation", "Saturation", "saturation", 0.0, 2.0,
DEFAULT_PROP_SATURATION,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstGLSinkBin::create-element:
* @object: the #GstGLSinkBin
*
* Will be emitted when we need the processing element/s that this bin will use
*
* Returns: a new #GstElement
*/
gst_gl_sink_bin_signals[SIGNAL_CREATE_ELEMENT] =
g_signal_new ("create-element", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
GST_TYPE_ELEMENT, 0);
gst_element_class_set_metadata (element_class,
"GL Sink Bin", "Sink/Video",
"Infrastructure to process GL textures",
"Matthew Waters <matthew@centricular.com>");
upload_caps = gst_gl_upload_get_input_template_caps ();
gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, upload_caps));
gst_caps_unref (upload_caps);
}
static void
gst_gl_sink_bin_init (GstGLSinkBin * self)
{
gboolean res = TRUE;
GstPad *pad;
self->upload = gst_element_factory_make ("glupload", NULL);
self->convert = gst_element_factory_make ("glcolorconvert", NULL);
self->balance = gst_element_factory_make ("glcolorbalance", NULL);
res &= gst_bin_add (GST_BIN (self), self->upload);
res &= gst_bin_add (GST_BIN (self), self->convert);
res &= gst_bin_add (GST_BIN (self), self->balance);
res &= gst_element_link_pads (self->upload, "src", self->convert, "sink");
res &= gst_element_link_pads (self->convert, "src", self->balance, "sink");
pad = gst_element_get_static_pad (self->upload, "sink");
if (!pad) {
res = FALSE;
} else {
GST_DEBUG_OBJECT (self, "setting target sink pad %" GST_PTR_FORMAT, pad);
self->sinkpad = gst_ghost_pad_new ("sink", pad);
gst_element_add_pad (GST_ELEMENT_CAST (self), self->sinkpad);
gst_object_unref (pad);
}
#define ADD_BINDING(obj,ref,prop) \
gst_object_add_control_binding (GST_OBJECT (obj), \
gst_proxy_control_binding_new (GST_OBJECT (obj), prop, \
GST_OBJECT (ref), prop));
ADD_BINDING (self->balance, self, "contrast");
ADD_BINDING (self->balance, self, "brightness");
ADD_BINDING (self->balance, self, "hue");
ADD_BINDING (self->balance, self, "saturation");
#undef ADD_BINDING
if (!res) {
GST_WARNING_OBJECT (self, "Failed to add/connect the necessary machinery");
}
}
static gboolean
_connect_sink_element (GstGLSinkBin * self)
{
gst_object_set_name (GST_OBJECT (self->sink), "sink");
if (gst_bin_add (GST_BIN (self), self->sink) &&
gst_element_link_pads (self->balance, "src", self->sink, "sink"))
return TRUE;
GST_ERROR_OBJECT (self, "Failed to link sink element into the pipeline");
return FALSE;
}
static void
gst_gl_sink_bin_set_sink (GstGLSinkBin * self, GstElement * sink)
{
g_return_if_fail (GST_IS_ELEMENT (sink));
if (self->sink) {
gst_bin_remove (GST_BIN (self), self->sink);
self->sink = NULL;
}
/* We keep an indirect reference when the element is added */
self->sink = sink;
if (sink && !_connect_sink_element (self))
self->sink = NULL;
}
void
gst_gl_sink_bin_finish_init_with_element (GstGLSinkBin * self,
GstElement * element)
{
gst_gl_sink_bin_set_sink (self, element);
}
void
gst_gl_sink_bin_finish_init (GstGLSinkBin * self)
{
GstGLSinkBinClass *klass = GST_GL_SINK_BIN_GET_CLASS (self);
GstElement *element = NULL;
if (klass->create_element)
element = klass->create_element ();
if (element)
gst_gl_sink_bin_set_sink (self, element);
}
static void
gst_gl_sink_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (object);
switch (prop_id) {
case PROP_SINK:
gst_gl_sink_bin_set_sink (self, g_value_get_object (value));
break;
case PROP_CONTRAST:
case PROP_BRIGHTNESS:
case PROP_HUE:
case PROP_SATURATION:
if (self->balance)
g_object_set_property (G_OBJECT (self->balance), pspec->name, value);
break;
default:
if (self->sink)
g_object_set_property (G_OBJECT (self->sink), pspec->name, value);
break;
}
}
static void
gst_gl_sink_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (object);
switch (prop_id) {
case PROP_SINK:
g_value_set_object (value, self->sink);
break;
case PROP_CONTRAST:
case PROP_BRIGHTNESS:
case PROP_HUE:
case PROP_SATURATION:
if (self->balance)
g_object_get_property (G_OBJECT (self->balance), pspec->name, value);
break;
default:
if (self->sink)
g_object_get_property (G_OBJECT (self->sink), pspec->name, value);
break;
}
}
static GstStateChangeReturn
gst_gl_sink_bin_change_state (GstElement * element, GstStateChange transition)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (element);
GstGLSinkBinClass *klass = GST_GL_SINK_BIN_GET_CLASS (self);
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GST_DEBUG ("changing state: %s => %s",
gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!self->sink) {
if (klass->create_element)
self->sink = klass->create_element ();
if (!self->sink)
g_signal_emit (element,
gst_gl_sink_bin_signals[SIGNAL_CREATE_ELEMENT], 0, &self->sink);
if (!self->sink) {
GST_ERROR_OBJECT (element, "Failed to retrieve element");
return GST_STATE_CHANGE_FAILURE;
}
if (!_connect_sink_element (self))
return GST_STATE_CHANGE_FAILURE;
}
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
default:
break;
}
return ret;
}
static void
gst_gl_sink_bin_navigation_send_event (GstNavigation * navigation, GstStructure
* structure)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (navigation);
GstElement *nav =
gst_bin_get_by_interface (GST_BIN (self), GST_TYPE_NAVIGATION);
if (nav) {
gst_navigation_send_event (GST_NAVIGATION (nav), structure);
structure = NULL;
gst_object_unref (nav);
} else {
GstEvent *event = gst_event_new_navigation (structure);
structure = NULL;
gst_element_send_event (GST_ELEMENT (self), event);
}
}
static void
gst_gl_sink_bin_navigation_interface_init (gpointer g_iface,
gpointer g_iface_data)
{
GstNavigationInterface *iface = (GstNavigationInterface *) g_iface;
iface->send_event = gst_gl_sink_bin_navigation_send_event;
}
static void
gst_gl_sink_bin_overlay_expose (GstVideoOverlay * overlay)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (overlay);
GstVideoOverlay *overlay_element = NULL;
overlay_element =
GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (self),
GST_TYPE_VIDEO_OVERLAY));
if (overlay_element) {
gst_video_overlay_expose (overlay_element);
gst_object_unref (overlay_element);
}
}
static void
gst_gl_sink_bin_overlay_handle_events (GstVideoOverlay * overlay,
gboolean handle_events)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (overlay);
GstVideoOverlay *overlay_element = NULL;
overlay_element =
GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (self),
GST_TYPE_VIDEO_OVERLAY));
if (overlay_element) {
gst_video_overlay_handle_events (overlay_element, handle_events);
gst_object_unref (overlay_element);
}
}
static void
gst_gl_sink_bin_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x,
gint y, gint width, gint height)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (overlay);
GstVideoOverlay *overlay_element = NULL;
overlay_element =
GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (self),
GST_TYPE_VIDEO_OVERLAY));
if (overlay_element) {
gst_video_overlay_set_render_rectangle (overlay_element, x, y, width,
height);
gst_object_unref (overlay_element);
}
}
static void
gst_gl_sink_bin_overlay_set_window_handle (GstVideoOverlay * overlay,
guintptr handle)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (overlay);
GstVideoOverlay *overlay_element = NULL;
overlay_element =
GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (self),
GST_TYPE_VIDEO_OVERLAY));
if (overlay_element) {
gst_video_overlay_set_window_handle (overlay_element, handle);
gst_object_unref (overlay_element);
}
}
static void
gst_gl_sink_bin_video_overlay_init (gpointer g_iface, gpointer g_iface_data)
{
GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface;
iface->expose = gst_gl_sink_bin_overlay_expose;
iface->handle_events = gst_gl_sink_bin_overlay_handle_events;
iface->set_render_rectangle = gst_gl_sink_bin_overlay_set_render_rectangle;
iface->set_window_handle = gst_gl_sink_bin_overlay_set_window_handle;
}
static const GList *
gst_gl_sink_bin_color_balance_list_channels (GstColorBalance * balance)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (balance);
GstColorBalance *balance_element = NULL;
const GList *list = NULL;
balance_element =
GST_COLOR_BALANCE (gst_bin_get_by_interface (GST_BIN (self),
GST_TYPE_COLOR_BALANCE));
if (balance_element) {
list = gst_color_balance_list_channels (balance_element);
gst_object_unref (balance_element);
}
return list;
}
static void
gst_gl_sink_bin_color_balance_set_value (GstColorBalance * balance,
GstColorBalanceChannel * channel, gint value)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (balance);
GstColorBalance *balance_element = NULL;
balance_element =
GST_COLOR_BALANCE (gst_bin_get_by_interface (GST_BIN (self),
GST_TYPE_COLOR_BALANCE));
if (balance_element) {
gst_color_balance_set_value (balance_element, channel, value);
gst_object_unref (balance_element);
}
}
static gint
gst_gl_sink_bin_color_balance_get_value (GstColorBalance * balance,
GstColorBalanceChannel * channel)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (balance);
GstColorBalance *balance_element = NULL;
gint val = 0;
balance_element =
GST_COLOR_BALANCE (gst_bin_get_by_interface (GST_BIN (self),
GST_TYPE_COLOR_BALANCE));
if (balance_element) {
val = gst_color_balance_get_value (balance_element, channel);
gst_object_unref (balance_element);
}
return val;
}
static GstColorBalanceType
gst_gl_sink_bin_color_balance_get_balance_type (GstColorBalance * balance)
{
GstGLSinkBin *self = GST_GL_SINK_BIN (balance);
GstColorBalance *balance_element = NULL;
GstColorBalanceType type = 0;
balance_element =
GST_COLOR_BALANCE (gst_bin_get_by_interface (GST_BIN (self),
GST_TYPE_COLOR_BALANCE));
if (balance_element) {
type = gst_color_balance_get_balance_type (balance_element);
gst_object_unref (balance_element);
}
return type;
}
static void
gst_gl_sink_bin_color_balance_init (gpointer g_iface, gpointer g_iface_data)
{
GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface;
iface->list_channels = gst_gl_sink_bin_color_balance_list_channels;
iface->set_value = gst_gl_sink_bin_color_balance_set_value;
iface->get_value = gst_gl_sink_bin_color_balance_get_value;
iface->get_balance_type = gst_gl_sink_bin_color_balance_get_balance_type;
}

View file

@ -1,76 +0,0 @@
/*
* 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 _GST_GL_SINK_BIN_H_
#define _GST_GL_SINK_BIN_H_
#include <gst/gst.h>
#include <gst/video/gstvideosink.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
GType gst_gl_sink_bin_get_type(void);
#define GST_TYPE_GL_SINK_BIN \
(gst_gl_sink_bin_get_type())
#define GST_GL_SINK_BIN(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_SINK_BIN,GstGLSinkBin))
#define GST_GL_SINK_BIN_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_SINK_BIN,GstGLSinkBinClass))
#define GST_IS_GL_SINK_BIN(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_SINK_BIN))
#define GST_IS_GL_SINK_BIN_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_SINK_BIN))
#define GST_GL_SINK_BIN_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_SINK_BIN,GstGLSinkBinClass))
typedef struct _GstGLSinkBin GstGLSinkBin;
typedef struct _GstGLSinkBinClass GstGLSinkBinClass;
struct _GstGLSinkBin
{
GstBin parent;
GstPad *sinkpad;
GstElement *upload;
GstElement *convert;
GstElement *balance;
GstElement *sink;
};
struct _GstGLSinkBinClass
{
GstBinClass parent_class;
GstElement * (*create_element) (void);
};
void gst_gl_sink_bin_finish_init (GstGLSinkBin * self);
void gst_gl_sink_bin_finish_init_with_element (GstGLSinkBin * self,
GstElement * element);
G_END_DECLS
#endif

View file

@ -1,267 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglsrcbin.h"
GST_DEBUG_CATEGORY (gst_debug_gl_src_bin);
#define GST_CAT_DEFAULT gst_debug_gl_src_bin
static void gst_gl_src_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * param_spec);
static void gst_gl_src_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * param_spec);
static GstStateChangeReturn gst_gl_src_bin_change_state (GstElement * element,
GstStateChange transition);
static GstStaticPadTemplate gst_gl_src_bin_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw(ANY)"));
enum
{
PROP_0,
PROP_SRC,
};
enum
{
SIGNAL_0,
SIGNAL_CREATE_ELEMENT,
SIGNAL_LAST,
};
static guint gst_gl_src_bin_signals[SIGNAL_LAST] = { 0, };
#define gst_gl_src_bin_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstGLSrcBin, gst_gl_src_bin,
GST_TYPE_BIN,
GST_DEBUG_CATEGORY_INIT (gst_debug_gl_src_bin, "glsrcbin", 0,
"OpenGL Video Src Bin"));
static void
gst_gl_src_bin_class_init (GstGLSrcBinClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
element_class->change_state = gst_gl_src_bin_change_state;
gobject_class->set_property = gst_gl_src_bin_set_property;
gobject_class->get_property = gst_gl_src_bin_get_property;
g_object_class_install_property (gobject_class, PROP_SRC,
g_param_spec_object ("src",
"GL src element",
"The GL src chain to use",
GST_TYPE_ELEMENT,
GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/**
* GstGLSrcBin::create-element:
* @object: the #GstGLSrcBin
*
* Will be emitted when we need the processing element/s that this bin will use
*
* Returns: a new #GstElement
*/
gst_gl_src_bin_signals[SIGNAL_CREATE_ELEMENT] =
g_signal_new ("create-element", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
GST_TYPE_ELEMENT, 0);
gst_element_class_set_metadata (element_class,
"GL Src Bin", "Src/Video",
"Infrastructure to process GL textures",
"Matthew Waters <matthew@centricular.com>");
gst_element_class_add_static_pad_template (element_class,
&gst_gl_src_bin_template);
}
static void
gst_gl_src_bin_init (GstGLSrcBin * self)
{
gboolean res = TRUE;
GstPad *pad;
self->download = gst_element_factory_make ("gldownload", NULL);
self->convert = gst_element_factory_make ("glcolorconvert", NULL);
res &= gst_bin_add (GST_BIN (self), self->download);
res &= gst_bin_add (GST_BIN (self), self->convert);
res &= gst_element_link_pads (self->convert, "src", self->download, "sink");
pad = gst_element_get_static_pad (self->download, "src");
if (!pad) {
res = FALSE;
} else {
GST_DEBUG_OBJECT (self, "setting target src pad %" GST_PTR_FORMAT, pad);
self->srcpad = gst_ghost_pad_new ("src", pad);
gst_element_add_pad (GST_ELEMENT_CAST (self), self->srcpad);
gst_object_unref (pad);
}
if (!res) {
GST_WARNING_OBJECT (self, "Failed to add/connect the necessary machinery");
}
}
static gboolean
_connect_src_element (GstGLSrcBin * self)
{
gboolean res = TRUE;
gst_object_set_name (GST_OBJECT (self->src), "src");
res &= gst_bin_add (GST_BIN (self), self->src);
res &= gst_element_link_pads (self->src, "src", self->convert, "sink");
if (!res)
GST_ERROR_OBJECT (self, "Failed to link src element into the pipeline");
return res;
}
void
gst_gl_src_bin_finish_init_with_element (GstGLSrcBin * self,
GstElement * element)
{
g_return_if_fail (GST_IS_ELEMENT (element));
self->src = element;
if (!_connect_src_element (self)) {
gst_object_unref (self->src);
self->src = NULL;
}
}
void
gst_gl_src_bin_finish_init (GstGLSrcBin * self)
{
GstGLSrcBinClass *klass = GST_GL_SRC_BIN_GET_CLASS (self);
GstElement *element = NULL;
if (klass->create_element)
element = klass->create_element ();
if (element)
gst_gl_src_bin_finish_init_with_element (self, element);
}
static void
gst_gl_src_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLSrcBin *self = GST_GL_SRC_BIN (object);
switch (prop_id) {
case PROP_SRC:
{
GstElement *src = g_value_get_object (value);
if (self->src)
gst_bin_remove (GST_BIN (self), self->src);
self->src = src;
if (src) {
gst_object_ref_sink (src);
_connect_src_element (self);
}
break;
}
default:
if (self->src)
g_object_set_property (G_OBJECT (self->src), pspec->name, value);
break;
}
}
static void
gst_gl_src_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLSrcBin *self = GST_GL_SRC_BIN (object);
switch (prop_id) {
case PROP_SRC:
g_value_set_object (value, self->src);
break;
default:
if (self->src)
g_object_get_property (G_OBJECT (self->src), pspec->name, value);
break;
}
}
static GstStateChangeReturn
gst_gl_src_bin_change_state (GstElement * element, GstStateChange transition)
{
GstGLSrcBin *self = GST_GL_SRC_BIN (element);
GstGLSrcBinClass *klass = GST_GL_SRC_BIN_GET_CLASS (self);
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GST_DEBUG ("changing state: %s => %s",
gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!self->src) {
if (klass->create_element)
self->src = klass->create_element ();
if (!self->src)
g_signal_emit (element,
gst_gl_src_bin_signals[SIGNAL_CREATE_ELEMENT], 0, &self->src);
if (!self->src) {
GST_ERROR_OBJECT (element, "Failed to retrieve element");
return GST_STATE_CHANGE_FAILURE;
}
if (!_connect_src_element (self))
return GST_STATE_CHANGE_FAILURE;
}
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
default:
break;
}
return ret;
}

View file

@ -1,71 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_SRC_BIN_H_
#define _GST_GL_SRC_BIN_H_
#include <gst/gst.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
GType gst_gl_src_bin_get_type(void);
#define GST_TYPE_GL_SRC_BIN \
(gst_gl_src_bin_get_type())
#define GST_GL_SRC_BIN(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_SRC_BIN,GstGLSrcBin))
#define GST_GL_SRC_BIN_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_SRC_BIN,GstGLSrcBinClass))
#define GST_IS_GL_SRC_BIN(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_SRC_BIN))
#define GST_IS_GL_SRC_BIN_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_SRC_BIN))
#define GST_GL_SRC_BIN_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_SRC_BIN,GstGLSrcBinClass))
typedef struct _GstGLSrcBin GstGLSrcBin;
typedef struct _GstGLSrcBinClass GstGLSrcBinClass;
struct _GstGLSrcBin
{
GstBin parent;
GstPad *srcpad;
GstElement *src;
GstElement *convert;
GstElement *download;
};
struct _GstGLSrcBinClass
{
GstBinClass parent_class;
GstElement * (*create_element) (void);
};
void gst_gl_src_bin_finish_init (GstGLSrcBin * self);
void gst_gl_src_bin_finish_init_with_element (GstGLSrcBin * self,
GstElement * element);
G_END_DECLS
#endif

View file

@ -1,735 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Jan Schmidt <jan@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glstereosplit
* @title: glstereosplit
*
* Receive a stereoscopic video stream and split into left/right
*
* ## Examples
* |[
* gst-launch-1.0 videotestsrc ! glstereosplit name=s ! queue ! glimagesink s. ! queue ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglstereosplit.h"
#define GST_CAT_DEFAULT gst_gl_stereosplit_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define SUPPORTED_GL_APIS GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_stereosplit_debug, "glstereosplit", 0, "glstereosplit element");
G_DEFINE_TYPE_WITH_CODE (GstGLStereoSplit, gst_gl_stereosplit,
GST_TYPE_ELEMENT, DEBUG_INIT);
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "RGBA"))
);
static GstStaticPadTemplate src_left_template = GST_STATIC_PAD_TEMPLATE ("left",
GST_PAD_SRC, GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "RGBA"))
);
static GstStaticPadTemplate src_right_template =
GST_STATIC_PAD_TEMPLATE ("right",
GST_PAD_SRC, GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
"RGBA"))
);
static void stereosplit_reset (GstGLStereoSplit * self);
static void stereosplit_finalize (GstGLStereoSplit * self);
static void stereosplit_set_context (GstElement * element,
GstContext * context);
static GstFlowReturn stereosplit_chain (GstPad * pad, GstGLStereoSplit * split,
GstBuffer * buf);
static GstStateChangeReturn stereosplit_change_state (GstElement * element,
GstStateChange transition);
static gboolean stereosplit_sink_query (GstPad * pad, GstObject * parent,
GstQuery * query);
static gboolean stereosplit_sink_event (GstPad * pad, GstObject * parent,
GstEvent * event);
static gboolean stereosplit_src_query (GstPad * pad, GstObject * parent,
GstQuery * query);
static gboolean stereosplit_src_event (GstPad * pad, GstObject * parent,
GstEvent * event);
static gboolean ensure_context (GstGLStereoSplit * self);
static void
gst_gl_stereosplit_class_init (GstGLStereoSplitClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_set_static_metadata (element_class,
"GLStereoSplit", "Codec/Converter",
"Splits a stereoscopic stream into separate left/right streams",
"Jan Schmidt <jan@centricular.com>\n"
"Matthew Waters <matthew@centricular.com>");
gobject_class->finalize = (GObjectFinalizeFunc) (stereosplit_finalize);
element_class->change_state = stereosplit_change_state;
element_class->set_context = stereosplit_set_context;
gst_element_class_add_static_pad_template (element_class, &sink_template);
gst_element_class_add_static_pad_template (element_class, &src_left_template);
gst_element_class_add_static_pad_template (element_class,
&src_right_template);
}
static void
gst_gl_stereosplit_init (GstGLStereoSplit * self)
{
GstPad *pad;
pad = self->sink_pad =
gst_pad_new_from_static_template (&sink_template, "sink");
gst_pad_set_chain_function (pad, (GstPadChainFunction) (stereosplit_chain));
gst_pad_set_query_function (pad, stereosplit_sink_query);
gst_pad_set_event_function (pad, stereosplit_sink_event);
gst_element_add_pad (GST_ELEMENT (self), self->sink_pad);
pad = self->left_pad =
gst_pad_new_from_static_template (&src_left_template, "left");
gst_pad_set_query_function (pad, stereosplit_src_query);
gst_pad_set_event_function (pad, stereosplit_src_event);
gst_element_add_pad (GST_ELEMENT (self), self->left_pad);
pad = self->right_pad =
gst_pad_new_from_static_template (&src_right_template, "right");
gst_pad_set_query_function (pad, stereosplit_src_query);
gst_pad_set_event_function (pad, stereosplit_src_event);
gst_element_add_pad (GST_ELEMENT (self), self->right_pad);
self->viewconvert = gst_gl_view_convert_new ();
}
static void
stereosplit_reset (GstGLStereoSplit * self)
{
if (self->context)
gst_object_replace ((GstObject **) & self->context, NULL);
if (self->display)
gst_object_replace ((GstObject **) & self->display, NULL);
}
static void
stereosplit_finalize (GstGLStereoSplit * self)
{
GObjectClass *klass = G_OBJECT_CLASS (gst_gl_stereosplit_parent_class);
if (self->viewconvert)
gst_object_replace ((GstObject **) & self->viewconvert, NULL);
klass->finalize ((GObject *) (self));
}
static void
stereosplit_set_context (GstElement * element, GstContext * context)
{
GstGLStereoSplit *stereosplit = GST_GL_STEREOSPLIT (element);
gst_gl_handle_set_context (element, context, &stereosplit->display,
&stereosplit->other_context);
if (stereosplit->display)
gst_gl_display_filter_gl_api (stereosplit->display, SUPPORTED_GL_APIS);
GST_ELEMENT_CLASS (gst_gl_stereosplit_parent_class)->set_context (element,
context);
}
static GstStateChangeReturn
stereosplit_change_state (GstElement * element, GstStateChange transition)
{
GstGLStereoSplit *stereosplit = GST_GL_STEREOSPLIT (element);
GstStateChangeReturn result;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!gst_gl_ensure_element_data (element, &stereosplit->display,
&stereosplit->other_context))
return GST_STATE_CHANGE_FAILURE;
gst_gl_display_filter_gl_api (stereosplit->display, SUPPORTED_GL_APIS);
break;
default:
break;
}
result =
GST_ELEMENT_CLASS (gst_gl_stereosplit_parent_class)->change_state
(element, transition);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_NULL:
if (stereosplit->other_context) {
gst_object_unref (stereosplit->other_context);
stereosplit->other_context = NULL;
}
if (stereosplit->display) {
gst_object_unref (stereosplit->display);
stereosplit->display = NULL;
}
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
stereosplit_reset (stereosplit);
break;
default:
break;
}
return result;
}
static GstCaps *
stereosplit_transform_caps (GstGLStereoSplit * self, GstPadDirection direction,
GstCaps * caps, GstCaps * filter)
{
GstCaps *next_caps;
/* FIXME: Is this the right way to ensure a context here ? */
if (!ensure_context (self))
return NULL;
next_caps =
gst_gl_view_convert_transform_caps (self->viewconvert, direction, caps,
NULL);
return next_caps;
}
static GstCaps *
strip_mview_fields (GstCaps * incaps, GstVideoMultiviewFlags keep_flags)
{
GstCaps *outcaps = gst_caps_make_writable (incaps);
gint i, n;
n = gst_caps_get_size (outcaps);
for (i = 0; i < n; i++) {
GstStructure *st = gst_caps_get_structure (outcaps, i);
GstVideoMultiviewFlags flags, mask;
gst_structure_remove_field (st, "multiview-mode");
if (gst_structure_get_flagset (st, "multiview-flags", (guint *) & flags,
(guint *) & mask)) {
flags &= keep_flags;
mask = keep_flags;
gst_structure_set (st, "multiview-flags",
GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, flags, mask, NULL);
}
}
return outcaps;
}
static gboolean stereosplit_do_bufferpool (GstGLStereoSplit * self,
GstCaps * caps);
static GstCaps *
stereosplit_get_src_caps (GstGLStereoSplit * split,
GstPad * pad, GstVideoMultiviewMode preferred_mode)
{
GstCaps *outcaps, *tmp, *templ_caps;
GValue item = G_VALUE_INIT, list = G_VALUE_INIT;
/* Get the template format */
templ_caps = gst_pad_get_pad_template_caps (pad);
/* And limit down to the preferred mode or mono */
templ_caps = gst_caps_make_writable (templ_caps);
g_value_init (&item, G_TYPE_STRING);
g_value_init (&list, GST_TYPE_LIST);
g_value_set_static_string (&item,
gst_video_multiview_mode_to_caps_string (preferred_mode));
gst_value_list_append_value (&list, &item);
g_value_set_static_string (&item,
gst_video_multiview_mode_to_caps_string (GST_VIDEO_MULTIVIEW_MODE_MONO));
gst_value_list_append_value (&list, &item);
gst_caps_set_value (templ_caps, "multiview-mode", &list);
g_value_unset (&list);
g_value_unset (&item);
/* And intersect with the peer */
if ((tmp = gst_pad_peer_query_caps (pad, NULL)) == NULL) {
gst_caps_unref (templ_caps);
return NULL;
}
outcaps = gst_caps_intersect_full (tmp, templ_caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (tmp);
gst_caps_unref (templ_caps);
GST_DEBUG_OBJECT (split, "Src pad %" GST_PTR_FORMAT " caps %" GST_PTR_FORMAT,
pad, outcaps);
return outcaps;
}
static gboolean
stereosplit_set_output_caps (GstGLStereoSplit * split, GstCaps * sinkcaps)
{
GstCaps *left = NULL, *right = NULL, *tridcaps = NULL;
GstCaps *tmp, *combined;
gboolean res = FALSE;
/* Choose some preferred output caps.
* Keep input width/height and PAR, preserve preferred output
* multiview flags for flipping/flopping if any, and set each
* left right pad to either left/mono and right/mono, as they prefer
*/
/* Calculate what downstream can collectively support */
left =
stereosplit_get_src_caps (split, split->left_pad,
GST_VIDEO_MULTIVIEW_MODE_LEFT);
if (left == NULL)
goto fail;
right =
stereosplit_get_src_caps (split, split->right_pad,
GST_VIDEO_MULTIVIEW_MODE_RIGHT);
if (right == NULL)
goto fail;
tridcaps = stereosplit_transform_caps (split, GST_PAD_SINK, sinkcaps, NULL);
if (!tridcaps || gst_caps_is_empty (tridcaps)) {
GST_ERROR_OBJECT (split,
"Failed to transform input caps %" GST_PTR_FORMAT, sinkcaps);
goto fail;
}
/* Preserve downstream preferred flipping/flopping */
tmp =
strip_mview_fields (gst_caps_ref (left),
GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLIPPED |
GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLOPPED);
combined = gst_caps_intersect (tridcaps, tmp);
gst_caps_unref (tridcaps);
gst_caps_unref (tmp);
tridcaps = combined;
tmp =
strip_mview_fields (gst_caps_ref (right),
GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLIPPED |
GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLOPPED);
combined = gst_caps_intersect (tridcaps, tmp);
gst_caps_unref (tridcaps);
gst_caps_unref (tmp);
tridcaps = combined;
if (G_UNLIKELY (gst_caps_is_empty (tridcaps))) {
gst_caps_unref (tridcaps);
goto fail;
}
/* Now generate the version for each output pad */
GST_DEBUG_OBJECT (split, "Attempting to set output caps %" GST_PTR_FORMAT,
tridcaps);
tmp = gst_caps_intersect (tridcaps, left);
gst_caps_unref (left);
left = tmp;
left = gst_caps_fixate (left);
if (!gst_pad_set_caps (split->left_pad, left)) {
GST_ERROR_OBJECT (split,
"Failed to set left output caps %" GST_PTR_FORMAT, left);
goto fail;
}
tmp = gst_caps_intersect (tridcaps, right);
gst_caps_unref (right);
right = tmp;
right = gst_caps_fixate (right);
if (!gst_pad_set_caps (split->right_pad, right)) {
GST_ERROR_OBJECT (split,
"Failed to set right output caps %" GST_PTR_FORMAT, right);
goto fail;
}
gst_gl_view_convert_set_context (split->viewconvert, split->context);
tridcaps = gst_caps_make_writable (tridcaps);
gst_caps_set_simple (tridcaps, "multiview-mode", G_TYPE_STRING,
"separated", "views", G_TYPE_INT, 2, NULL);
tridcaps = gst_caps_fixate (tridcaps);
if (!gst_gl_view_convert_set_caps (split->viewconvert, sinkcaps, tridcaps)) {
GST_ERROR_OBJECT (split, "Failed to set caps on converter");
goto fail;
}
/* FIXME: Provide left and right caps to do_bufferpool */
stereosplit_do_bufferpool (split, left);
res = TRUE;
fail:
if (left)
gst_caps_unref (left);
if (right)
gst_caps_unref (right);
if (tridcaps)
gst_caps_unref (tridcaps);
return res;
}
static gboolean
_find_local_gl_context (GstGLStereoSplit * split)
{
if (gst_gl_query_local_gl_context (GST_ELEMENT (split), GST_PAD_SRC,
&split->context))
return TRUE;
if (gst_gl_query_local_gl_context (GST_ELEMENT (split), GST_PAD_SINK,
&split->context))
return TRUE;
return FALSE;
}
static gboolean
ensure_context (GstGLStereoSplit * self)
{
GError *error = NULL;
if (!gst_gl_ensure_element_data (self, &self->display, &self->other_context))
return FALSE;
gst_gl_display_filter_gl_api (self->display, SUPPORTED_GL_APIS);
_find_local_gl_context (self);
if (!self->context) {
GST_OBJECT_LOCK (self->display);
do {
if (self->context)
gst_object_unref (self->context);
/* just get a GL context. we don't care */
self->context =
gst_gl_display_get_gl_context_for_thread (self->display, NULL);
if (!self->context) {
if (!gst_gl_display_create_context (self->display, self->other_context,
&self->context, &error)) {
GST_OBJECT_UNLOCK (self->display);
goto context_error;
}
}
} while (!gst_gl_display_add_context (self->display, self->context));
GST_OBJECT_UNLOCK (self->display);
}
{
GstGLAPI current_gl_api = gst_gl_context_get_gl_api (self->context);
if ((current_gl_api & (SUPPORTED_GL_APIS)) == 0)
goto unsupported_gl_api;
}
return TRUE;
unsupported_gl_api:
{
GstGLAPI gl_api = gst_gl_context_get_gl_api (self->context);
gchar *gl_api_str = gst_gl_api_to_string (gl_api);
gchar *supported_gl_api_str = gst_gl_api_to_string (SUPPORTED_GL_APIS);
GST_ELEMENT_ERROR (self, RESOURCE, BUSY,
("GL API's not compatible context: %s supported: %s", gl_api_str,
supported_gl_api_str), (NULL));
g_free (supported_gl_api_str);
g_free (gl_api_str);
return FALSE;
}
context_error:
{
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND, ("%s", error->message),
(NULL));
g_clear_error (&error);
return FALSE;
}
}
static gboolean
stereosplit_decide_allocation (GstGLStereoSplit * self, GstQuery * query)
{
if (!ensure_context (self))
return FALSE;
return TRUE;
}
static gboolean
stereosplit_propose_allocation (GstGLStereoSplit * self, GstQuery * query)
{
if (!gst_gl_ensure_element_data (self, &self->display, &self->other_context))
return FALSE;
return TRUE;
}
static gboolean
stereosplit_do_bufferpool (GstGLStereoSplit * self, GstCaps * caps)
{
GstQuery *query;
query = gst_query_new_allocation (caps, TRUE);
if (!gst_pad_peer_query (self->left_pad, query)) {
if (!gst_pad_peer_query (self->right_pad, query)) {
GST_DEBUG_OBJECT (self, "peer ALLOCATION query failed on both src pads");
}
}
if (!stereosplit_decide_allocation (self, query)) {
gst_query_unref (query);
return FALSE;
}
gst_query_unref (query);
return TRUE;
}
static GstFlowReturn
stereosplit_chain (GstPad * pad, GstGLStereoSplit * split, GstBuffer * buf)
{
GstBuffer *left, *right;
GstBuffer *split_buffer = NULL;
GstFlowReturn ret;
gint i, n_planes;
n_planes = GST_VIDEO_INFO_N_PLANES (&split->viewconvert->out_info);
GST_LOG_OBJECT (split, "chaining buffer %" GST_PTR_FORMAT, buf);
if (gst_gl_view_convert_submit_input_buffer (split->viewconvert,
GST_BUFFER_IS_DISCONT (buf), buf) != GST_FLOW_OK) {
GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s",
"Failed to 3d convert buffer"),
("Could not get submit input buffer"));
return GST_FLOW_ERROR;
}
ret = gst_gl_view_convert_get_output (split->viewconvert, &split_buffer);
if (ret != GST_FLOW_OK) {
GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s",
"Failed to 3d convert buffer"), ("Could not get output buffer"));
return GST_FLOW_ERROR;
}
if (split_buffer == NULL)
return GST_FLOW_OK; /* Need another input buffer */
left = gst_buffer_new ();
gst_buffer_copy_into (left, buf,
GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
GST_BUFFER_FLAG_UNSET (left, GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE);
gst_buffer_add_parent_buffer_meta (left, split_buffer);
for (i = 0; i < n_planes; i++) {
GstMemory *mem = gst_buffer_get_memory (split_buffer, i);
gst_buffer_append_memory (left, mem);
}
ret = gst_pad_push (split->left_pad, gst_buffer_ref (left));
/* Allow unlinked on the first pad - as long as the 2nd isn't unlinked */
gst_buffer_unref (left);
if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)) {
gst_buffer_unref (split_buffer);
return ret;
}
right = gst_buffer_new ();
gst_buffer_copy_into (right, buf,
GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
GST_BUFFER_FLAG_UNSET (left, GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE);
gst_buffer_add_parent_buffer_meta (right, split_buffer);
for (i = n_planes; i < n_planes * 2; i++) {
GstMemory *mem = gst_buffer_get_memory (split_buffer, i);
gst_buffer_append_memory (right, mem);
}
ret = gst_pad_push (split->right_pad, gst_buffer_ref (right));
gst_buffer_unref (right);
gst_buffer_unref (split_buffer);
return ret;
}
static gboolean
stereosplit_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
GstGLStereoSplit *split = GST_GL_STEREOSPLIT (parent);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
{
if (gst_gl_handle_context_query ((GstElement *) split, query,
split->display, split->context, split->other_context))
return TRUE;
return gst_pad_query_default (pad, parent, query);
}
/* FIXME: Handle caps query */
default:
return gst_pad_query_default (pad, parent, query);
}
}
static gboolean
stereosplit_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
return gst_pad_event_default (pad, parent, event);
}
static gboolean
stereosplit_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
GstGLStereoSplit *split = GST_GL_STEREOSPLIT (parent);
GST_DEBUG_OBJECT (split, "sink query %s",
gst_query_type_get_name (GST_QUERY_TYPE (query)));
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
{
if (gst_gl_handle_context_query ((GstElement *) split, query,
split->display, split->context, split->other_context))
return TRUE;
return gst_pad_query_default (pad, parent, query);
}
case GST_QUERY_ALLOCATION:
{
return stereosplit_propose_allocation (split, query);
}
case GST_QUERY_ACCEPT_CAPS:
{
GstCaps *possible, *caps;
gboolean allowed;
gst_query_parse_accept_caps (query, &caps);
if (!(possible = gst_pad_query_caps (split->sink_pad, caps)))
return FALSE;
allowed = gst_caps_is_subset (caps, possible);
gst_caps_unref (possible);
gst_query_set_accept_caps_result (query, allowed);
return allowed;
}
case GST_QUERY_CAPS:
{
GstCaps *filter, *left, *right, *combined, *ret, *templ_caps;
gst_query_parse_caps (query, &filter);
/* Calculate what downstream can collectively support */
if (!(left = gst_pad_peer_query_caps (split->left_pad, NULL)))
return FALSE;
if (!(right = gst_pad_peer_query_caps (split->right_pad, NULL)))
return FALSE;
/* Strip out multiview mode and flags that might break the
* intersection, since we can convert.
* We could keep downstream preferred flip/flopping and list
* separated as preferred in the future which might
* theoretically allow us an easier conversion, but it's not essential
*/
left = strip_mview_fields (left, GST_VIDEO_MULTIVIEW_FLAGS_NONE);
right = strip_mview_fields (right, GST_VIDEO_MULTIVIEW_FLAGS_NONE);
combined = gst_caps_intersect (left, right);
gst_caps_unref (left);
gst_caps_unref (right);
/* Intersect peer caps with our template formats */
templ_caps = gst_pad_get_pad_template_caps (split->left_pad);
ret =
gst_caps_intersect_full (combined, templ_caps,
GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (templ_caps);
gst_caps_unref (combined);
combined = ret;
if (!combined || gst_caps_is_empty (combined)) {
gst_caps_unref (combined);
return FALSE;
}
/* Convert from the src pad caps to input formats we support */
ret = stereosplit_transform_caps (split, GST_PAD_SRC, combined, filter);
gst_caps_unref (combined);
combined = ret;
/* Intersect with the sink pad template then */
templ_caps = gst_pad_get_pad_template_caps (split->sink_pad);
ret =
gst_caps_intersect_full (combined, templ_caps,
GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (templ_caps);
GST_LOG_OBJECT (split, "Returning sink pad caps %" GST_PTR_FORMAT, ret);
gst_query_set_caps_result (query, ret);
return !gst_caps_is_empty (ret);
}
default:
return gst_pad_query_default (pad, parent, query);
}
}
static gboolean
stereosplit_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
GstGLStereoSplit *split = GST_GL_STEREOSPLIT (parent);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
{
GstCaps *caps;
gst_event_parse_caps (event, &caps);
return stereosplit_set_output_caps (split, caps);
}
default:
return gst_pad_event_default (pad, parent, event);
}
}

View file

@ -1,64 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Jan Schmidt <jan@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_STEREOSPLIT_H__
#define __GST_GL_STEREOSPLIT_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_STEREOSPLIT (gst_gl_stereosplit_get_type())
#define GST_GL_STEREOSPLIT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_STEREOSPLIT,GstGLStereoSplit))
#define GST_IS_GL_STEREOSPLIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_STEREOSPLIT))
#define GST_GL_STEREOSPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_STEREOSPLIT,GstGLStereoSplitClass))
#define GST_IS_GL_STEREOSPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_STEREOSPLIT))
#define GST_GL_STEREOSPLIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_STEREOSPLIT,GstGLStereoSplitClass))
typedef struct _GstGLStereoSplit GstGLStereoSplit;
typedef struct _GstGLStereoSplitClass GstGLStereoSplitClass;
struct _GstGLStereoSplit
{
GstElement parent;
GstPad *sink_pad;
GstPad *left_pad;
GstPad *right_pad;
GstGLDisplay *display;
GstGLContext *context;
GstGLContext *other_context;
GstGLViewConvert *viewconvert;
};
struct _GstGLStereoSplitClass
{
GstElementClass parent_class;
};
GType gst_gl_stereosplit_get_type (void);
G_END_DECLS
#endif

View file

@ -1,771 +0,0 @@
/*
* 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>
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-gltestsrc
* @title: gltestsrc
*
* The gltestsrc element is used to produce test video texture.
* The video test produced can be controlled with the "pattern"
* property.
*
* ## Example launch line
*
* |[
* gst-launch-1.0 -v gltestsrc pattern=smpte ! glimagesink
* ]|
* Shows original SMPTE color bars in a window.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglfuncs.h>
#include <gst/gst-i18n-plugin.h>
#include "gstgltestsrc.h"
#include "gltestsrc.h"
#define USE_PEER_BUFFERALLOC
#define SUPPORTED_GL_APIS (GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2)
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 */
};
/* *INDENT-OFF* */
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), "
"format = (string) RGBA, "
"width = " GST_VIDEO_SIZE_RANGE ", "
"height = " GST_VIDEO_SIZE_RANGE ", "
"framerate = " GST_VIDEO_FPS_RANGE ","
"texture-target = (string) 2D")
);
/* *INDENT-ON* */
#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 GstStateChangeReturn gst_gl_test_src_change_state (GstElement * element,
GstStateChange transition);
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 gboolean gst_gl_test_src_callback (gpointer stuff);
static gboolean gst_gl_test_src_init_shader (GstGLTestSrc * gltestsrc);
#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"},
{GST_GL_TEST_SRC_MANDELBROT, "Mandelbrot Fractal", "mandelbrot"},
{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_static_pad_template (element_class, &src_factory);
element_class->set_context = gst_gl_test_src_set_context;
element_class->change_state = gst_gl_test_src_change_state;
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->set_pattern = pattern_type;
}
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->set_pattern);
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;
gst_caps_replace (&gltestsrc->out_caps, caps);
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,
&src->other_context);
if (src->display)
gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS);
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
}
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:
{
if (gst_gl_handle_context_query ((GstElement *) src, query,
src->display, src->context, src->other_context))
return TRUE;
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);
return res;
}
default:
break;
}
return GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
}
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 gboolean
gst_gl_test_src_init_shader (GstGLTestSrc * gltestsrc)
{
if (gst_gl_context_get_gl_api (gltestsrc->context)) {
/* blocking call, wait until the opengl thread has compiled the shader */
// if (gltestsrc->vertex_src == NULL)
// return FALSE;
// return gst_gl_context_gen_shader (gltestsrc->context, gltestsrc->vertex_src,
// gltestsrc->fragment_src, &gltestsrc->shader);
}
return TRUE;
}
static void
_fill_gl (GstGLContext * context, GstGLTestSrc * src)
{
src->gl_result = gst_gl_framebuffer_draw_to_texture (src->fbo, src->out_tex,
gst_gl_test_src_callback, src);
}
static GstFlowReturn
gst_gl_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (psrc);
GstClockTime next_time;
GstVideoFrame out_frame;
GstGLSyncMeta *sync_meta;
if (G_UNLIKELY (!src->negotiated || !src->context))
goto not_negotiated;
/* 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 (!gst_video_frame_map (&out_frame, &src->out_info, buffer,
GST_MAP_WRITE | GST_MAP_GL)) {
return GST_FLOW_NOT_NEGOTIATED;
}
src->out_tex = (GstGLMemory *) out_frame.map[0].memory;
gst_gl_context_thread_add (src->context, (GstGLContextThreadFunc) _fill_gl,
src);
if (!src->gl_result) {
gst_video_frame_unmap (&out_frame);
goto gl_error;
}
gst_video_frame_unmap (&out_frame);
if (!src->gl_result)
goto gl_error;
sync_meta = gst_buffer_get_gl_sync_meta (buffer);
if (sync_meta)
gst_gl_sync_meta_set_sync_point (sync_meta, src->context);
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;
gl_error:
{
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (_("failed to draw pattern")),
(_("A GL error occurred")));
return GST_FLOW_NOT_NEGOTIATED;
}
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_element_data (src, &src->display, &src->other_context))
return FALSE;
gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS);
src->running_time = 0;
src->n_frames = 0;
src->negotiated = FALSE;
return TRUE;
}
static void
gst_gl_test_src_gl_stop (GstGLContext * context, GstGLTestSrc * src)
{
if (src->fbo)
gst_object_unref (src->fbo);
src->fbo = NULL;
if (src->shader)
gst_object_unref (src->shader);
src->shader = NULL;
if (src->src_impl)
src->src_funcs->free (src->src_impl);
src->src_impl = NULL;
}
static gboolean
gst_gl_test_src_stop (GstBaseSrc * basesrc)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (basesrc);
if (src->context)
gst_gl_context_thread_add (src->context,
(GstGLContextThreadFunc) gst_gl_test_src_gl_stop, src);
gst_caps_replace (&src->out_caps, NULL);
if (src->context)
gst_object_unref (src->context);
src->context = NULL;
return TRUE;
}
static gboolean
_find_local_gl_context (GstGLTestSrc * src)
{
if (gst_gl_query_local_gl_context (GST_ELEMENT (src), GST_PAD_SRC,
&src->context))
return TRUE;
return FALSE;
}
static void
_src_generate_fbo_gl (GstGLContext * context, GstGLTestSrc * src)
{
src->fbo = gst_gl_framebuffer_new_with_default_depth (src->context,
GST_VIDEO_INFO_WIDTH (&src->out_info),
GST_VIDEO_INFO_HEIGHT (&src->out_info));
}
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;
if (!gst_gl_ensure_element_data (src, &src->display, &src->other_context))
return FALSE;
gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS);
_find_local_gl_context (src);
if (!src->context) {
GST_OBJECT_LOCK (src->display);
do {
if (src->context) {
gst_object_unref (src->context);
src->context = NULL;
}
/* just get a GL context. we don't care */
src->context =
gst_gl_display_get_gl_context_for_thread (src->display, NULL);
if (!src->context) {
if (!gst_gl_display_create_context (src->display, src->other_context,
&src->context, &error)) {
GST_OBJECT_UNLOCK (src->display);
goto context_error;
}
}
} while (!gst_gl_display_add_context (src->display, src->context));
GST_OBJECT_UNLOCK (src->display);
}
if ((gst_gl_context_get_gl_api (src->context) & SUPPORTED_GL_APIS) == 0)
goto unsupported_gl_api;
gst_gl_context_thread_add (src->context,
(GstGLContextThreadFunc) _src_generate_fbo_gl, src);
if (!src->fbo)
goto context_error;
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 (!pool || !GST_IS_GL_BUFFER_POOL (pool)) {
/* can't use this pool */
if (pool)
gst_object_unref (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);
if (gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL))
gst_buffer_pool_config_add_option (config,
GST_BUFFER_POOL_OPTION_GL_SYNC_META);
gst_buffer_pool_config_add_option (config,
GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_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_gl_test_src_init_shader (src);
gst_object_unref (pool);
return TRUE;
unsupported_gl_api:
{
GstGLAPI gl_api = gst_gl_context_get_gl_api (src->context);
gchar *gl_api_str = gst_gl_api_to_string (gl_api);
gchar *supported_gl_api_str = gst_gl_api_to_string (SUPPORTED_GL_APIS);
GST_ELEMENT_ERROR (src, RESOURCE, BUSY,
("GL API's not compatible context: %s supported: %s", gl_api_str,
supported_gl_api_str), (NULL));
g_free (supported_gl_api_str);
g_free (gl_api_str);
return FALSE;
}
context_error:
{
if (error) {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s", error->message),
(NULL));
g_clear_error (&error);
} else {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), (NULL));
}
if (src->context)
gst_object_unref (src->context);
src->context = NULL;
return FALSE;
}
}
static gboolean
gst_gl_test_src_callback (gpointer stuff)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (stuff);
const struct SrcFuncs *funcs;
funcs = src->src_funcs;
if (!funcs || src->set_pattern != src->active_pattern) {
if (src->src_impl && funcs)
funcs->free (src->src_impl);
src->src_funcs = funcs =
gst_gl_test_src_get_src_funcs_for_pattern (src->set_pattern);
if (funcs == NULL) {
GST_ERROR_OBJECT (src, "Could not find an implementation of the "
"requested pattern");
return FALSE;
}
src->src_impl = funcs->new (src);
if (!(src->gl_result =
funcs->init (src->src_impl, src->context, &src->out_info))) {
GST_ERROR_OBJECT (src, "Failed to initialize pattern");
return FALSE;
}
src->active_pattern = src->set_pattern;
}
return funcs->fill_bound_fbo (src->src_impl);
}
static GstStateChangeReturn
gst_gl_test_src_change_state (GstElement * element, GstStateChange transition)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (element);
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GST_DEBUG_OBJECT (src, "changing state: %s => %s",
gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!gst_gl_ensure_element_data (element, &src->display,
&src->other_context))
return GST_STATE_CHANGE_FAILURE;
gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS);
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
case GST_STATE_CHANGE_READY_TO_NULL:
if (src->other_context) {
gst_object_unref (src->other_context);
src->other_context = NULL;
}
if (src->display) {
gst_object_unref (src->display);
src->display = NULL;
}
break;
default:
break;
}
return ret;
}

View file

@ -1,94 +0,0 @@
/*
* 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>
#include "gltestsrc.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))
typedef struct _GstGLTestSrcClass GstGLTestSrcClass;
/**
* GstGLTestSrc:
*
* Opaque data structure.
*/
struct _GstGLTestSrc {
GstPushSrc element;
/*< private >*/
/* type of output */
GstGLTestSrcPattern set_pattern;
GstGLTestSrcPattern active_pattern;
/* video state */
GstVideoInfo out_info;
GstGLFramebuffer *fbo;
GstGLMemory *out_tex;
GstGLShader *shader;
GstBufferPool *pool;
GstGLDisplay *display;
GstGLContext *context, *other_context;
gint64 timestamp_offset; /* base offset */
GstClockTime running_time; /* total running time */
gint64 n_frames; /* total frames sent */
gboolean negotiated;
gboolean gl_result;
const struct SrcFuncs *src_funcs;
gpointer src_impl;
GstCaps *out_caps;
};
struct _GstGLTestSrcClass {
GstPushSrcClass parent_class;
};
GType gst_gl_test_src_get_type (void);
G_END_DECLS
#endif /* __GST_GL_TEST_SRC_H__ */

View file

@ -1,970 +0,0 @@
/*
* GStreamer
* Copyright (C) 2014 Lubosz Sarnecki <lubosz@gmail.com>
* Copyright (C) 2016 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-gltransformation
* @title: gltransformation
*
* Transforms video on the GPU.
*
* ## Examples
* |[
* gst-launch-1.0 gltestsrc ! gltransformation rotation-z=45 ! glimagesink
* ]| A pipeline to rotate by 45 degrees
* |[
* gst-launch-1.0 gltestsrc ! gltransformation translation-x=0.5 ! glimagesink
* ]| Translate the video by 0.5
* |[
* gst-launch-1.0 gltestsrc ! gltransformation scale-y=0.5 scale-x=0.5 ! glimagesink
* ]| Resize the video by 0.5
* |[
* gst-launch-1.0 gltestsrc ! gltransformation rotation-x=-45 ortho=True ! glimagesink
* ]| Rotate the video around the X-Axis by -45° with an orthographic projection
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstgltransformation.h"
#include <gst/gl/gstglapi.h>
#include <graphene-gobject.h>
#include "gstglutils.h"
#define GST_CAT_DEFAULT gst_gl_transformation_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define gst_gl_transformation_parent_class parent_class
#define VEC4_FORMAT "%f,%f,%f,%f"
#define VEC4_ARGS(v) graphene_vec4_get_x (v), graphene_vec4_get_y (v), graphene_vec4_get_z (v), graphene_vec4_get_w (v)
#define VEC3_FORMAT "%f,%f,%f"
#define VEC3_ARGS(v) graphene_vec3_get_x (v), graphene_vec3_get_y (v), graphene_vec3_get_z (v)
#define VEC2_FORMAT "%f,%f"
#define VEC2_ARGS(v) graphene_vec2_get_x (v), graphene_vec2_get_y (v)
#define POINT3D_FORMAT "%f,%f,%f"
#define POINT3D_ARGS(p) (p)->x, (p)->y, (p)->z
enum
{
PROP_0,
PROP_FOV,
PROP_ORTHO,
PROP_TRANSLATION_X,
PROP_TRANSLATION_Y,
PROP_TRANSLATION_Z,
PROP_ROTATION_X,
PROP_ROTATION_Y,
PROP_ROTATION_Z,
PROP_SCALE_X,
PROP_SCALE_Y,
PROP_MVP,
PROP_PIVOT_X,
PROP_PIVOT_Y,
PROP_PIVOT_Z,
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_transformation_debug, "gltransformation", 0, "gltransformation element");
G_DEFINE_TYPE_WITH_CODE (GstGLTransformation, gst_gl_transformation,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_transformation_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_transformation_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_gl_transformation_set_caps (GstGLFilter * filter,
GstCaps * incaps, GstCaps * outcaps);
static gboolean gst_gl_transformation_src_event (GstBaseTransform * trans,
GstEvent * event);
static gboolean gst_gl_transformation_filter_meta (GstBaseTransform * trans,
GstQuery * query, GType api, const GstStructure * params);
static gboolean gst_gl_transformation_decide_allocation (GstBaseTransform *
trans, GstQuery * query);
static void gst_gl_transformation_gl_stop (GstGLBaseFilter * filter);
static gboolean gst_gl_transformation_gl_start (GstGLBaseFilter * base_filter);
static gboolean gst_gl_transformation_callback (gpointer stuff);
static void gst_gl_transformation_build_mvp (GstGLTransformation *
transformation);
static GstFlowReturn
gst_gl_transformation_prepare_output_buffer (GstBaseTransform * trans,
GstBuffer * inbuf, GstBuffer ** outbuf);
static gboolean gst_gl_transformation_filter (GstGLFilter * filter,
GstBuffer * inbuf, GstBuffer * outbuf);
static gboolean gst_gl_transformation_filter_texture (GstGLFilter * filter,
GstGLMemory * in_tex, GstGLMemory * out_tex);
static void
gst_gl_transformation_class_init (GstGLTransformationClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
GstBaseTransformClass *base_transform_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
base_transform_class = GST_BASE_TRANSFORM_CLASS (klass);
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
gobject_class->set_property = gst_gl_transformation_set_property;
gobject_class->get_property = gst_gl_transformation_get_property;
base_transform_class->src_event = gst_gl_transformation_src_event;
base_transform_class->decide_allocation =
gst_gl_transformation_decide_allocation;
base_transform_class->filter_meta = gst_gl_transformation_filter_meta;
GST_GL_BASE_FILTER_CLASS (klass)->gl_start = gst_gl_transformation_gl_start;
GST_GL_BASE_FILTER_CLASS (klass)->gl_stop = gst_gl_transformation_gl_stop;
GST_GL_FILTER_CLASS (klass)->set_caps = gst_gl_transformation_set_caps;
GST_GL_FILTER_CLASS (klass)->filter = gst_gl_transformation_filter;
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_transformation_filter_texture;
GST_BASE_TRANSFORM_CLASS (klass)->prepare_output_buffer =
gst_gl_transformation_prepare_output_buffer;
g_object_class_install_property (gobject_class, PROP_FOV,
g_param_spec_float ("fov", "Fov", "Field of view angle in degrees",
0.0, G_MAXFLOAT, 90.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ORTHO,
g_param_spec_boolean ("ortho", "Orthographic",
"Use orthographic projection", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* Rotation */
g_object_class_install_property (gobject_class, PROP_ROTATION_X,
g_param_spec_float ("rotation-x", "X Rotation",
"Rotates the video around the X-Axis in degrees.",
-G_MAXFLOAT, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ROTATION_Y,
g_param_spec_float ("rotation-y", "Y Rotation",
"Rotates the video around the Y-Axis in degrees.",
-G_MAXFLOAT, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ROTATION_Z,
g_param_spec_float ("rotation-z", "Z Rotation",
"Rotates the video around the Z-Axis in degrees.",
-G_MAXFLOAT, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* Translation */
g_object_class_install_property (gobject_class, PROP_TRANSLATION_X,
g_param_spec_float ("translation-x", "X Translation",
"Translates the video at the X-Axis, in universal [0-1] coordinate.",
-G_MAXFLOAT, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_TRANSLATION_Y,
g_param_spec_float ("translation-y", "Y Translation",
"Translates the video at the Y-Axis, in universal [0-1] coordinate.",
-G_MAXFLOAT, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_TRANSLATION_Z,
g_param_spec_float ("translation-z", "Z Translation",
"Translates the video at the Z-Axis, in universal [0-1] coordinate.",
-G_MAXFLOAT, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* Scale */
g_object_class_install_property (gobject_class, PROP_SCALE_X,
g_param_spec_float ("scale-x", "X Scale",
"Scale multiplier for the X-Axis.",
-G_MAXFLOAT, G_MAXFLOAT, 1.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SCALE_Y,
g_param_spec_float ("scale-y", "Y Scale",
"Scale multiplier for the Y-Axis.",
-G_MAXFLOAT, G_MAXFLOAT, 1.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* Pivot */
g_object_class_install_property (gobject_class, PROP_PIVOT_X,
g_param_spec_float ("pivot-x", "X Pivot",
"Rotation pivot point X coordinate, where 0 is the center,"
" -1 the left border, +1 the right border and <-1, >1 outside.",
-G_MAXFLOAT, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PIVOT_Y,
g_param_spec_float ("pivot-y", "Y Pivot",
"Rotation pivot point X coordinate, where 0 is the center,"
" -1 the left border, +1 the right border and <-1, >1 outside.",
-G_MAXFLOAT, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PIVOT_Z,
g_param_spec_float ("pivot-z", "Z Pivot",
"Relevant for rotation in 3D space. You look into the negative Z axis direction",
-G_MAXFLOAT, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* MVP */
g_object_class_install_property (gobject_class, PROP_MVP,
g_param_spec_boxed ("mvp-matrix",
"Modelview Projection Matrix",
"The final Graphene 4x4 Matrix for transformation",
GRAPHENE_TYPE_MATRIX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (element_class, "OpenGL transformation filter",
"Filter/Effect/Video", "Transform video on the GPU",
"Lubosz Sarnecki <lubosz@gmail.com>\n"
"Matthew Waters <matthew@centricular.com>");
GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api =
GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2;
}
static void
gst_gl_transformation_init (GstGLTransformation * filter)
{
filter->shader = NULL;
filter->fov = 90;
filter->aspect = 1.0;
filter->znear = 0.1f;
filter->zfar = 100.0;
filter->xscale = 1.0;
filter->yscale = 1.0;
filter->in_tex = 0;
gst_gl_transformation_build_mvp (filter);
}
static void
gst_gl_transformation_build_mvp (GstGLTransformation * transformation)
{
GstGLFilter *filter = GST_GL_FILTER (transformation);
graphene_matrix_t modelview_matrix;
if (!filter->out_info.finfo) {
graphene_matrix_init_identity (&transformation->model_matrix);
graphene_matrix_init_identity (&transformation->view_matrix);
graphene_matrix_init_identity (&transformation->projection_matrix);
} else {
graphene_point3d_t translation_vector =
GRAPHENE_POINT3D_INIT (transformation->xtranslation * 2.0 *
transformation->aspect,
transformation->ytranslation * 2.0,
transformation->ztranslation * 2.0);
graphene_point3d_t pivot_vector =
GRAPHENE_POINT3D_INIT (-transformation->xpivot * transformation->aspect,
transformation->ypivot,
-transformation->zpivot);
graphene_point3d_t negative_pivot_vector;
graphene_vec3_t center;
graphene_vec3_t up;
gboolean current_passthrough;
gboolean passthrough;
graphene_vec3_init (&transformation->camera_position, 0.f, 0.f, 1.f);
graphene_vec3_init (&center, 0.f, 0.f, 0.f);
graphene_vec3_init (&up, 0.f, 1.f, 0.f);
/* Translate into pivot origin */
graphene_matrix_init_translate (&transformation->model_matrix,
&pivot_vector);
/* Scale */
graphene_matrix_scale (&transformation->model_matrix,
transformation->xscale, transformation->yscale, 1.0f);
/* Rotation */
graphene_matrix_rotate (&transformation->model_matrix,
transformation->xrotation, graphene_vec3_x_axis ());
graphene_matrix_rotate (&transformation->model_matrix,
transformation->yrotation, graphene_vec3_y_axis ());
graphene_matrix_rotate (&transformation->model_matrix,
transformation->zrotation, graphene_vec3_z_axis ());
/* Translate back from pivot origin */
graphene_point3d_scale (&pivot_vector, -1.0, &negative_pivot_vector);
graphene_matrix_translate (&transformation->model_matrix,
&negative_pivot_vector);
/* Translation */
graphene_matrix_translate (&transformation->model_matrix,
&translation_vector);
if (transformation->ortho) {
graphene_matrix_init_ortho (&transformation->projection_matrix,
-transformation->aspect, transformation->aspect,
-1, 1, transformation->znear, transformation->zfar);
} else {
graphene_matrix_init_perspective (&transformation->projection_matrix,
transformation->fov,
transformation->aspect, transformation->znear, transformation->zfar);
}
graphene_matrix_init_look_at (&transformation->view_matrix,
&transformation->camera_position, &center, &up);
current_passthrough =
gst_base_transform_is_passthrough (GST_BASE_TRANSFORM (transformation));
passthrough = transformation->xtranslation == 0.
&& transformation->ytranslation == 0.
&& transformation->ztranslation == 0. && transformation->xrotation == 0.
&& transformation->yrotation == 0. && transformation->zrotation == 0.
&& transformation->xscale == 1. && transformation->yscale == 1.
&& gst_video_info_is_equal (&filter->in_info, &filter->out_info);
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (transformation),
passthrough);
if (current_passthrough != passthrough) {
gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (transformation));
}
}
graphene_matrix_multiply (&transformation->model_matrix,
&transformation->view_matrix, &modelview_matrix);
graphene_matrix_multiply (&modelview_matrix,
&transformation->projection_matrix, &transformation->mvp_matrix);
graphene_matrix_inverse (&transformation->model_matrix,
&transformation->inv_model_matrix);
graphene_matrix_inverse (&transformation->view_matrix,
&transformation->inv_view_matrix);
graphene_matrix_inverse (&transformation->projection_matrix,
&transformation->inv_projection_matrix);
}
static void
gst_gl_transformation_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLTransformation *filter = GST_GL_TRANSFORMATION (object);
switch (prop_id) {
case PROP_FOV:
filter->fov = g_value_get_float (value);
break;
case PROP_ORTHO:
filter->ortho = g_value_get_boolean (value);
break;
case PROP_TRANSLATION_X:
filter->xtranslation = g_value_get_float (value);
break;
case PROP_TRANSLATION_Y:
filter->ytranslation = g_value_get_float (value);
break;
case PROP_TRANSLATION_Z:
filter->ztranslation = g_value_get_float (value);
break;
case PROP_ROTATION_X:
filter->xrotation = g_value_get_float (value);
break;
case PROP_ROTATION_Y:
filter->yrotation = g_value_get_float (value);
break;
case PROP_ROTATION_Z:
filter->zrotation = g_value_get_float (value);
break;
case PROP_SCALE_X:
filter->xscale = g_value_get_float (value);
break;
case PROP_SCALE_Y:
filter->yscale = g_value_get_float (value);
break;
case PROP_PIVOT_X:
filter->xpivot = g_value_get_float (value);
break;
case PROP_PIVOT_Y:
filter->ypivot = g_value_get_float (value);
break;
case PROP_PIVOT_Z:
filter->zpivot = g_value_get_float (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
gst_gl_transformation_build_mvp (filter);
}
static void
gst_gl_transformation_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLTransformation *filter = GST_GL_TRANSFORMATION (object);
switch (prop_id) {
case PROP_FOV:
g_value_set_float (value, filter->fov);
break;
case PROP_ORTHO:
g_value_set_boolean (value, filter->ortho);
break;
case PROP_TRANSLATION_X:
g_value_set_float (value, filter->xtranslation);
break;
case PROP_TRANSLATION_Y:
g_value_set_float (value, filter->ytranslation);
break;
case PROP_TRANSLATION_Z:
g_value_set_float (value, filter->ztranslation);
break;
case PROP_ROTATION_X:
g_value_set_float (value, filter->xrotation);
break;
case PROP_ROTATION_Y:
g_value_set_float (value, filter->yrotation);
break;
case PROP_ROTATION_Z:
g_value_set_float (value, filter->zrotation);
break;
case PROP_SCALE_X:
g_value_set_float (value, filter->xscale);
break;
case PROP_SCALE_Y:
g_value_set_float (value, filter->yscale);
break;
case PROP_PIVOT_X:
g_value_set_float (value, filter->xpivot);
break;
case PROP_PIVOT_Y:
g_value_set_float (value, filter->ypivot);
break;
case PROP_PIVOT_Z:
g_value_set_float (value, filter->zpivot);
break;
case PROP_MVP:
/* FIXME: need to decompose this to support navigation events */
g_value_set_boxed (value, (gconstpointer) & filter->mvp_matrix);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_transformation_set_caps (GstGLFilter * filter, GstCaps * incaps,
GstCaps * outcaps)
{
GstGLTransformation *transformation = GST_GL_TRANSFORMATION (filter);
transformation->aspect =
(gdouble) GST_VIDEO_INFO_WIDTH (&filter->out_info) /
(gdouble) GST_VIDEO_INFO_HEIGHT (&filter->out_info);
transformation->caps_change = TRUE;
gst_gl_transformation_build_mvp (transformation);
return TRUE;
}
static void
_intersect_plane_and_ray (graphene_plane_t * video_plane, graphene_ray_t * ray,
graphene_point3d_t * result)
{
float t = graphene_ray_get_distance_to_plane (ray, video_plane);
GST_TRACE ("Calculated a distance of %f to the plane", t);
graphene_ray_get_position_at (ray, t, result);
}
static void
_screen_coord_to_world_ray (GstGLTransformation * transformation, float x,
float y, graphene_ray_t * ray)
{
GstGLFilter *filter = GST_GL_FILTER (transformation);
gfloat w = (gfloat) GST_VIDEO_INFO_WIDTH (&filter->in_info);
gfloat h = (gfloat) GST_VIDEO_INFO_HEIGHT (&filter->in_info);
graphene_vec3_t ray_eye_vec3, ray_world_dir, *ray_origin, *ray_direction;
graphene_vec3_t ray_ortho_dir;
graphene_point3d_t ray_clip, ray_eye;
graphene_vec2_t screen_coord;
/* GL is y-flipped. i.e. 0, 0 is the bottom left corner in screen space */
graphene_vec2_init (&screen_coord, (2. * x / w - 1.) / transformation->aspect,
1. - 2. * y / h);
graphene_point3d_init (&ray_clip, graphene_vec2_get_x (&screen_coord),
graphene_vec2_get_y (&screen_coord), -1.);
graphene_matrix_transform_point3d (&transformation->inv_projection_matrix,
&ray_clip, &ray_eye);
graphene_vec3_init (&ray_eye_vec3, ray_eye.x, ray_eye.y, -1.);
if (transformation->ortho) {
graphene_vec3_init (&ray_ortho_dir, 0., 0., 1.);
ray_origin = &ray_eye_vec3;
ray_direction = &ray_ortho_dir;
} else {
graphene_matrix_transform_vec3 (&transformation->inv_view_matrix,
&ray_eye_vec3, &ray_world_dir);
graphene_vec3_normalize (&ray_world_dir, &ray_world_dir);
ray_origin = &transformation->camera_position;
ray_direction = &ray_world_dir;
}
graphene_ray_init_from_vec3 (ray, ray_origin, ray_direction);
GST_TRACE_OBJECT (transformation, "Calculated ray origin: " VEC3_FORMAT
" direction: " VEC3_FORMAT " from screen coordinates: " VEC2_FORMAT
" with %s projection",
VEC3_ARGS (ray_origin), VEC3_ARGS (ray_direction),
VEC2_ARGS (&screen_coord),
transformation->ortho ? "ortho" : "perspection");
}
static void
_init_world_video_plane (GstGLTransformation * transformation,
graphene_plane_t * video_plane)
{
graphene_point3d_t bottom_left, bottom_right, top_left, top_right;
graphene_point3d_t world_bottom_left, world_bottom_right;
graphene_point3d_t world_top_left, world_top_right;
graphene_point3d_init (&top_left, -transformation->aspect, 1., 0.);
graphene_point3d_init (&top_right, transformation->aspect, 1., 0.);
graphene_point3d_init (&bottom_left, -transformation->aspect, -1., 0.);
graphene_point3d_init (&bottom_right, transformation->aspect, -1., 0.);
graphene_matrix_transform_point3d (&transformation->model_matrix,
&bottom_left, &world_bottom_left);
graphene_matrix_transform_point3d (&transformation->model_matrix,
&bottom_right, &world_bottom_right);
graphene_matrix_transform_point3d (&transformation->model_matrix,
&top_left, &world_top_left);
graphene_matrix_transform_point3d (&transformation->model_matrix,
&top_right, &world_top_right);
graphene_plane_init_from_points (video_plane, &world_bottom_left,
&world_top_right, &world_top_left);
}
static gboolean
_screen_coord_to_model_coord (GstGLTransformation * transformation,
double x, double y, double *res_x, double *res_y)
{
GstGLFilter *filter = GST_GL_FILTER (transformation);
double w = (double) GST_VIDEO_INFO_WIDTH (&filter->in_info);
double h = (double) GST_VIDEO_INFO_HEIGHT (&filter->in_info);
graphene_point3d_t world_point, model_coord;
graphene_plane_t video_plane;
graphene_ray_t ray;
double new_x, new_y;
_init_world_video_plane (transformation, &video_plane);
_screen_coord_to_world_ray (transformation, x, y, &ray);
_intersect_plane_and_ray (&video_plane, &ray, &world_point);
graphene_matrix_transform_point3d (&transformation->inv_model_matrix,
&world_point, &model_coord);
/* ndc to pixels. We render the frame Y-flipped so need to unflip the
* y coordinate */
new_x = (model_coord.x + 1.) * w / 2;
new_y = (1. - model_coord.y) * h / 2;
if (new_x < 0. || new_x > w || new_y < 0. || new_y > h)
/* coords off video surface */
return FALSE;
GST_DEBUG_OBJECT (transformation, "converted %f,%f to %f,%f", x, y, new_x,
new_y);
if (res_x)
*res_x = new_x;
if (res_y)
*res_y = new_y;
return TRUE;
}
#if 0
/* debugging facilities for transforming vertices from model space to screen
* space */
static void
_ndc_to_viewport (GstGLTransformation * transformation, graphene_vec3_t * ndc,
int x, int y, int w, int h, float near, float far, graphene_vec3_t * result)
{
GstGLFilter *filter = GST_GL_FILTER (transformation);
/* center of the viewport */
int o_x = x + w / 2;
int o_y = y + h / 2;
graphene_vec3_init (result, graphene_vec3_get_x (ndc) * w / 2 + o_x,
graphene_vec3_get_y (ndc) * h / 2 + o_y,
(far - near) * graphene_vec3_get_z (ndc) / 2 + (far + near) / 2);
}
static void
_perspective_division (graphene_vec4_t * clip, graphene_vec3_t * result)
{
float w = graphene_vec4_get_w (clip);
graphene_vec3_init (result, graphene_vec4_get_x (clip) / w,
graphene_vec4_get_y (clip) / w, graphene_vec4_get_z (clip) / w);
}
static void
_vertex_to_screen_coord (GstGLTransformation * transformation,
graphene_vec4_t * vertex, graphene_vec3_t * view)
{
GstGLFilter *filter = GST_GL_FILTER (transformation);
gint w = GST_VIDEO_INFO_WIDTH (&filter->in_info);
gint h = GST_VIDEO_INFO_HEIGHT (&filter->in_info);
graphene_vec4_t clip;
graphene_vec3_t ndc;
graphene_matrix_transform_vec4 (&transformation->mvp_matrix, vertex, &clip);
_perspective_division (&clip, &ndc);
_ndc_to_viewport (transformation, &ndc, 0, 0, w, h, 0., 1., view);
}
#endif
static gboolean
gst_gl_transformation_src_event (GstBaseTransform * trans, GstEvent * event)
{
GstGLTransformation *transformation = GST_GL_TRANSFORMATION (trans);
GstStructure *structure;
gboolean ret;
GST_DEBUG_OBJECT (trans, "handling %s event", GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NAVIGATION:{
gdouble x, y;
event =
GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
structure = (GstStructure *) gst_event_get_structure (event);
if (gst_structure_get_double (structure, "pointer_x", &x) &&
gst_structure_get_double (structure, "pointer_y", &y)) {
gdouble new_x, new_y;
if (!_screen_coord_to_model_coord (transformation, x, y, &new_x,
&new_y)) {
gst_event_unref (event);
return TRUE;
}
gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, new_x,
"pointer_y", G_TYPE_DOUBLE, new_y, NULL);
}
break;
}
default:
break;
}
ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
return ret;
}
static gboolean
gst_gl_transformation_filter_meta (GstBaseTransform * trans, GstQuery * query,
GType api, const GstStructure * params)
{
if (api == GST_VIDEO_AFFINE_TRANSFORMATION_META_API_TYPE)
return TRUE;
if (api == GST_GL_SYNC_META_API_TYPE)
return TRUE;
return FALSE;
}
static gboolean
gst_gl_transformation_decide_allocation (GstBaseTransform * trans,
GstQuery * query)
{
GstGLTransformation *transformation = GST_GL_TRANSFORMATION (trans);
if (!GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
query))
return FALSE;
if (gst_query_find_allocation_meta (query,
GST_VIDEO_AFFINE_TRANSFORMATION_META_API_TYPE, NULL)) {
transformation->downstream_supports_affine_meta = TRUE;
} else {
transformation->downstream_supports_affine_meta = FALSE;
}
return TRUE;
}
static void
gst_gl_transformation_gl_stop (GstGLBaseFilter * base_filter)
{
GstGLTransformation *transformation = GST_GL_TRANSFORMATION (base_filter);
const GstGLFuncs *gl = base_filter->context->gl_vtable;
if (transformation->vao) {
gl->DeleteVertexArrays (1, &transformation->vao);
transformation->vao = 0;
}
if (transformation->vertex_buffer) {
gl->DeleteBuffers (1, &transformation->vertex_buffer);
transformation->vertex_buffer = 0;
}
if (transformation->vbo_indices) {
gl->DeleteBuffers (1, &transformation->vbo_indices);
transformation->vbo_indices = 0;
}
if (transformation->shader) {
gst_object_unref (transformation->shader);
transformation->shader = NULL;
}
GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
}
static gboolean
gst_gl_transformation_gl_start (GstGLBaseFilter * base_filter)
{
GstGLTransformation *transformation = GST_GL_TRANSFORMATION (base_filter);
if (!GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter))
return FALSE;
if (gst_gl_context_get_gl_api (base_filter->context)) {
/* blocking call, wait until the opengl thread has compiled the shader */
return gst_gl_context_gen_shader (base_filter->context,
gst_gl_shader_string_vertex_mat4_vertex_transform,
gst_gl_shader_string_fragment_default, &transformation->shader);
}
return TRUE;
}
static GstFlowReturn
gst_gl_transformation_prepare_output_buffer (GstBaseTransform * trans,
GstBuffer * inbuf, GstBuffer ** outbuf)
{
GstGLTransformation *transformation = GST_GL_TRANSFORMATION (trans);
GstGLFilter *filter = GST_GL_FILTER (trans);
if (transformation->downstream_supports_affine_meta &&
gst_video_info_is_equal (&filter->in_info, &filter->out_info)) {
GstVideoAffineTransformationMeta *af_meta;
graphene_matrix_t upstream_matrix, tmp, tmp2, inv_aspect, yflip;
float upstream[16], downstream[16];
*outbuf = gst_buffer_make_writable (inbuf);
af_meta = gst_buffer_get_video_affine_transformation_meta (inbuf);
if (!af_meta)
af_meta = gst_buffer_add_video_affine_transformation_meta (*outbuf);
GST_LOG_OBJECT (trans, "applying transformation to existing affine "
"transformation meta");
gst_gl_get_affine_transformation_meta_as_ndc_ext (af_meta, upstream);
/* apply the transformation to the existing affine meta */
graphene_matrix_init_from_float (&upstream_matrix, upstream);
graphene_matrix_init_scale (&inv_aspect, transformation->aspect, -1., 1.);
graphene_matrix_init_scale (&yflip, 1., -1., 1.);
/* invert the aspect effects */
graphene_matrix_multiply (&upstream_matrix, &inv_aspect, &tmp2);
/* apply the transformation */
graphene_matrix_multiply (&tmp2, &transformation->mvp_matrix, &tmp);
/* and undo yflip */
graphene_matrix_multiply (&tmp, &yflip, &tmp2);
graphene_matrix_to_float (&tmp2, downstream);
gst_gl_set_affine_transformation_meta_from_ndc_ext (af_meta, downstream);
return GST_FLOW_OK;
}
return GST_BASE_TRANSFORM_CLASS (parent_class)->prepare_output_buffer (trans,
inbuf, outbuf);
}
static gboolean
gst_gl_transformation_filter (GstGLFilter * filter,
GstBuffer * inbuf, GstBuffer * outbuf)
{
GstGLTransformation *transformation = GST_GL_TRANSFORMATION (filter);
if (transformation->downstream_supports_affine_meta &&
gst_video_info_is_equal (&filter->in_info, &filter->out_info)) {
return TRUE;
} else {
return gst_gl_filter_filter_texture (filter, inbuf, outbuf);
}
}
static gboolean
gst_gl_transformation_filter_texture (GstGLFilter * filter,
GstGLMemory * in_tex, GstGLMemory * out_tex)
{
GstGLTransformation *transformation = GST_GL_TRANSFORMATION (filter);
transformation->in_tex = in_tex;
gst_gl_framebuffer_draw_to_texture (filter->fbo, out_tex,
(GstGLFramebufferFunc) gst_gl_transformation_callback, transformation);
return TRUE;
}
static const GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
static void
_upload_vertices (GstGLTransformation * transformation)
{
const GstGLFuncs *gl =
GST_GL_BASE_FILTER (transformation)->context->gl_vtable;
/* *INDENT-OFF* */
GLfloat vertices[] = {
-transformation->aspect, -1.0, 0.0, 1.0, 0.0, 0.0,
transformation->aspect, -1.0, 0.0, 1.0, 1.0, 0.0,
transformation->aspect, 1.0, 0.0, 1.0, 1.0, 1.0,
-transformation->aspect, 1.0, 0.0, 1.0, 0.0, 1.0,
};
/* *INDENT-ON* */
gl->BindBuffer (GL_ARRAY_BUFFER, transformation->vertex_buffer);
gl->BufferData (GL_ARRAY_BUFFER, 4 * 6 * sizeof (GLfloat), vertices,
GL_STATIC_DRAW);
}
static void
_bind_buffer (GstGLTransformation * transformation)
{
const GstGLFuncs *gl =
GST_GL_BASE_FILTER (transformation)->context->gl_vtable;
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, transformation->vbo_indices);
gl->BindBuffer (GL_ARRAY_BUFFER, transformation->vertex_buffer);
/* Load the vertex position */
gl->VertexAttribPointer (transformation->attr_position, 4, GL_FLOAT,
GL_FALSE, 6 * sizeof (GLfloat), (void *) 0);
/* Load the texture coordinate */
gl->VertexAttribPointer (transformation->attr_texture, 2, GL_FLOAT, GL_FALSE,
6 * sizeof (GLfloat), (void *) (4 * sizeof (GLfloat)));
gl->EnableVertexAttribArray (transformation->attr_position);
gl->EnableVertexAttribArray (transformation->attr_texture);
}
static void
_unbind_buffer (GstGLTransformation * transformation)
{
const GstGLFuncs *gl =
GST_GL_BASE_FILTER (transformation)->context->gl_vtable;
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
gl->BindBuffer (GL_ARRAY_BUFFER, 0);
gl->DisableVertexAttribArray (transformation->attr_position);
gl->DisableVertexAttribArray (transformation->attr_texture);
}
static gboolean
gst_gl_transformation_callback (gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLTransformation *transformation = GST_GL_TRANSFORMATION (filter);
GstGLFuncs *gl = GST_GL_BASE_FILTER (filter)->context->gl_vtable;
GLfloat temp_matrix[16];
gst_gl_context_clear_shader (GST_GL_BASE_FILTER (filter)->context);
gl->BindTexture (GL_TEXTURE_2D, 0);
gl->ClearColor (0.f, 0.f, 0.f, 0.f);
gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gst_gl_shader_use (transformation->shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, transformation->in_tex->tex_id);
gst_gl_shader_set_uniform_1i (transformation->shader, "texture", 0);
graphene_matrix_to_float (&transformation->mvp_matrix, temp_matrix);
gst_gl_shader_set_uniform_matrix_4fv (transformation->shader,
"u_transformation", 1, GL_FALSE, temp_matrix);
if (!transformation->vertex_buffer) {
transformation->attr_position =
gst_gl_shader_get_attribute_location (transformation->shader,
"a_position");
transformation->attr_texture =
gst_gl_shader_get_attribute_location (transformation->shader,
"a_texcoord");
if (gl->GenVertexArrays) {
gl->GenVertexArrays (1, &transformation->vao);
gl->BindVertexArray (transformation->vao);
}
gl->GenBuffers (1, &transformation->vertex_buffer);
gl->GenBuffers (1, &transformation->vbo_indices);
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, transformation->vbo_indices);
gl->BufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indices), indices,
GL_STATIC_DRAW);
transformation->caps_change = TRUE;
}
if (gl->GenVertexArrays)
gl->BindVertexArray (transformation->vao);
if (transformation->caps_change)
_upload_vertices (transformation);
_bind_buffer (transformation);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
if (gl->GenVertexArrays)
gl->BindVertexArray (0);
_unbind_buffer (transformation);
gst_gl_context_clear_shader (GST_GL_BASE_FILTER (filter)->context);
transformation->caps_change = FALSE;
return TRUE;
}

View file

@ -1,99 +0,0 @@
/*
* GStreamer
* Copyright (C) 2014 Lubosz Sarnecki <lubosz@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_TRANSFORMATION_H_
#define _GST_GL_TRANSFORMATION_H_
#include <gst/gl/gstglfilter.h>
#include <gst/gl/gstglfuncs.h>
#include <graphene.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_TRANSFORMATION (gst_gl_transformation_get_type())
#define GST_GL_TRANSFORMATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_TRANSFORMATION,GstGLTransformation))
#define GST_IS_GL_TRANSFORMATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_TRANSFORMATION))
#define GST_GL_TRANSFORMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_TRANSFORMATION,GstGLTransformationClass))
#define GST_IS_GL_TRANSFORMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_TRANSFORMATION))
#define GST_GL_TRANSFORMATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_TRANSFORMATION,GstGLTransformationClass))
typedef struct _GstGLTransformation GstGLTransformation;
typedef struct _GstGLTransformationClass GstGLTransformationClass;
struct _GstGLTransformation
{
GstGLFilter filter;
GstGLShader *shader;
GLuint vao;
GLuint vbo_indices;
GLuint vertex_buffer;
GLint attr_position;
GLint attr_texture;
GstGLMemory *in_tex;
GstGLMemory *out_tex;
gfloat xrotation;
gfloat yrotation;
gfloat zrotation;
gfloat xscale;
gfloat yscale;
gfloat xtranslation;
gfloat ytranslation;
gfloat ztranslation;
gfloat xpivot;
gfloat ypivot;
gfloat zpivot;
/* perspective */
gfloat fov;
gfloat aspect;
gfloat znear;
gfloat zfar;
gboolean ortho;
graphene_matrix_t model_matrix;
graphene_matrix_t view_matrix;
graphene_matrix_t projection_matrix;
graphene_matrix_t inv_model_matrix;
graphene_matrix_t inv_view_matrix;
graphene_matrix_t inv_projection_matrix;
graphene_matrix_t mvp_matrix;
graphene_vec3_t camera_position;
gboolean downstream_supports_affine_meta;
gboolean caps_change;
};
struct _GstGLTransformationClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_transformation_get_type (void);
G_END_DECLS
#endif /* _GST_GL_TRANSFORMATION_H_ */

View file

@ -1,270 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <gst/gl/gl.h>
#include "gstgluploadelement.h"
GST_DEBUG_CATEGORY_STATIC (gst_gl_upload_element_debug);
#define GST_CAT_DEFAULT gst_gl_upload_element_debug
#define gst_gl_upload_element_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstGLUploadElement, gst_gl_upload_element,
GST_TYPE_GL_BASE_FILTER,
GST_DEBUG_CATEGORY_INIT (gst_gl_upload_element_debug, "gluploadelement", 0,
"glupload Element"););
static gboolean gst_gl_upload_element_get_unit_size (GstBaseTransform * trans,
GstCaps * caps, gsize * size);
static GstCaps *_gst_gl_upload_element_transform_caps (GstBaseTransform * bt,
GstPadDirection direction, GstCaps * caps, GstCaps * filter);
static gboolean _gst_gl_upload_element_set_caps (GstBaseTransform * bt,
GstCaps * in_caps, GstCaps * out_caps);
static gboolean gst_gl_upload_element_filter_meta (GstBaseTransform * trans,
GstQuery * query, GType api, const GstStructure * params);
static gboolean _gst_gl_upload_element_propose_allocation (GstBaseTransform *
bt, GstQuery * decide_query, GstQuery * query);
static gboolean _gst_gl_upload_element_decide_allocation (GstBaseTransform *
trans, GstQuery * query);
static GstFlowReturn
gst_gl_upload_element_prepare_output_buffer (GstBaseTransform * bt,
GstBuffer * buffer, GstBuffer ** outbuf);
static GstFlowReturn gst_gl_upload_element_transform (GstBaseTransform * bt,
GstBuffer * buffer, GstBuffer * outbuf);
static gboolean gst_gl_upload_element_stop (GstBaseTransform * bt);
static GstStaticPadTemplate gst_gl_upload_element_src_pad_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw(ANY)"));
static void
gst_gl_upload_element_finalize (GObject * object)
{
GstGLUploadElement *upload = GST_GL_UPLOAD_ELEMENT (object);
if (upload->upload)
gst_object_unref (upload->upload);
upload->upload = NULL;
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_gl_upload_element_class_init (GstGLUploadElementClass * klass)
{
GstBaseTransformClass *bt_class = GST_BASE_TRANSFORM_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstCaps *upload_caps;
bt_class->transform_caps = _gst_gl_upload_element_transform_caps;
bt_class->set_caps = _gst_gl_upload_element_set_caps;
bt_class->filter_meta = gst_gl_upload_element_filter_meta;
bt_class->propose_allocation = _gst_gl_upload_element_propose_allocation;
bt_class->decide_allocation = _gst_gl_upload_element_decide_allocation;
bt_class->get_unit_size = gst_gl_upload_element_get_unit_size;
bt_class->prepare_output_buffer = gst_gl_upload_element_prepare_output_buffer;
bt_class->transform = gst_gl_upload_element_transform;
bt_class->stop = gst_gl_upload_element_stop;
bt_class->passthrough_on_same_caps = TRUE;
gst_element_class_add_static_pad_template (element_class,
&gst_gl_upload_element_src_pad_template);
upload_caps = gst_gl_upload_get_input_template_caps ();
gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, upload_caps));
gst_caps_unref (upload_caps);
gst_element_class_set_metadata (element_class,
"OpenGL uploader", "Filter/Video",
"Uploads data into OpenGL", "Matthew Waters <matthew@centricular.com>");
gobject_class->finalize = gst_gl_upload_element_finalize;
}
static void
gst_gl_upload_element_init (GstGLUploadElement * upload)
{
gst_base_transform_set_prefer_passthrough (GST_BASE_TRANSFORM (upload), TRUE);
}
static gboolean
gst_gl_upload_element_stop (GstBaseTransform * bt)
{
GstGLUploadElement *upload = GST_GL_UPLOAD_ELEMENT (bt);
if (upload->upload) {
gst_object_unref (upload->upload);
upload->upload = NULL;
}
gst_caps_replace (&upload->in_caps, NULL);
gst_caps_replace (&upload->out_caps, NULL);
return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (bt);
}
static gboolean
gst_gl_upload_element_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
gsize * size)
{
gboolean ret = FALSE;
GstVideoInfo info;
ret = gst_video_info_from_caps (&info, caps);
if (ret)
*size = GST_VIDEO_INFO_SIZE (&info);
return TRUE;
}
static GstCaps *
_gst_gl_upload_element_transform_caps (GstBaseTransform * bt,
GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{
GstGLUploadElement *upload = GST_GL_UPLOAD_ELEMENT (bt);
GstGLContext *context = GST_GL_BASE_FILTER (bt)->context;
if (upload->upload == NULL)
upload->upload = gst_gl_upload_new (NULL);
return gst_gl_upload_transform_caps (upload->upload, context, direction, caps,
filter);
}
static gboolean
gst_gl_upload_element_filter_meta (GstBaseTransform * trans, GstQuery * query,
GType api, const GstStructure * params)
{
/* propose all metadata upstream */
return TRUE;
}
static gboolean
_gst_gl_upload_element_propose_allocation (GstBaseTransform * bt,
GstQuery * decide_query, GstQuery * query)
{
GstGLUploadElement *upload = GST_GL_UPLOAD_ELEMENT (bt);
gboolean ret;
if (!upload->upload)
return FALSE;
ret = GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (bt,
decide_query, query);
gst_gl_upload_propose_allocation (upload->upload, decide_query, query);
return ret;
}
static gboolean
_gst_gl_upload_element_decide_allocation (GstBaseTransform * trans,
GstQuery * query)
{
GstGLUploadElement *upload = GST_GL_UPLOAD_ELEMENT (trans);
GstGLContext *context;
gboolean ret;
ret =
GST_BASE_TRANSFORM_CLASS
(gst_gl_upload_element_parent_class)->decide_allocation (trans, query);
if (!ret)
return FALSE;
/* GstGLBaseFilter populates ->context in ::decide_allocation so now it's the
* time to set the ->upload context */
context = GST_GL_BASE_FILTER (trans)->context;
gst_gl_upload_set_context (upload->upload, context);
return gst_gl_upload_set_caps (upload->upload, upload->in_caps,
upload->out_caps);
}
static gboolean
_gst_gl_upload_element_set_caps (GstBaseTransform * bt, GstCaps * in_caps,
GstCaps * out_caps)
{
GstGLUploadElement *upload = GST_GL_UPLOAD_ELEMENT (bt);
gst_caps_replace (&upload->in_caps, in_caps);
gst_caps_replace (&upload->out_caps, out_caps);
if (upload->upload)
return gst_gl_upload_set_caps (upload->upload, in_caps, out_caps);
return TRUE;
}
GstFlowReturn
gst_gl_upload_element_prepare_output_buffer (GstBaseTransform * bt,
GstBuffer * buffer, GstBuffer ** outbuf)
{
GstGLUploadElement *upload = GST_GL_UPLOAD_ELEMENT (bt);
GstGLUploadReturn ret;
GstBaseTransformClass *bclass;
bclass = GST_BASE_TRANSFORM_GET_CLASS (bt);
if (gst_base_transform_is_passthrough (bt)) {
*outbuf = buffer;
return GST_FLOW_OK;
}
if (!upload->upload)
return GST_FLOW_NOT_NEGOTIATED;
ret = gst_gl_upload_perform_with_buffer (upload->upload, buffer, outbuf);
if (ret == GST_GL_UPLOAD_RECONFIGURE) {
gst_base_transform_reconfigure_src (bt);
return GST_FLOW_OK;
}
if (ret != GST_GL_UPLOAD_DONE || *outbuf == NULL) {
GST_ELEMENT_ERROR (bt, RESOURCE, NOT_FOUND, ("%s",
"Failed to upload buffer"), (NULL));
if (*outbuf)
gst_buffer_unref (*outbuf);
return GST_FLOW_ERROR;
}
/* basetransform doesn't unref if they're the same */
if (buffer == *outbuf)
gst_buffer_unref (*outbuf);
else
bclass->copy_metadata (bt, buffer, *outbuf);
return GST_FLOW_OK;
}
static GstFlowReturn
gst_gl_upload_element_transform (GstBaseTransform * bt, GstBuffer * buffer,
GstBuffer * outbuf)
{
return GST_FLOW_OK;
}

View file

@ -1,69 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_UPLOAD_ELEMENT_H__
#define __GST_GL_UPLOAD_ELEMENT_H__
#include <gst/video/video.h>
#include <gst/gl/gstgl_fwd.h>
G_BEGIN_DECLS
GType gst_gl_upload_element_get_type (void);
#define GST_TYPE_GL_UPLOAD_ELEMENT (gst_gl_upload_element_get_type())
#define GST_GL_UPLOAD_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_UPLOAD_ELEMENT,GstGLUploadElement))
#define GST_GL_UPLOAD_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_UPLOAD_ELEMENT,GstGLUploadElementClass))
#define GST_IS_GL_UPLOAD_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_UPLOAD_ELEMENT))
#define GST_IS_GL_UPLOAD_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_UPLOAD_ELEMENT))
#define GST_GL_UPLOAD_ELEMENT_CAST(obj) ((GstGLUploadElement*)(obj))
typedef struct _GstGLUploadElement GstGLUploadElement;
typedef struct _GstGLUploadElementClass GstGLUploadElementClass;
typedef struct _GstGLUploadElementPrivate GstGLUploadElementPrivate;
/**
* GstGLUploadElement
*
* Opaque #GstGLUploadElement object
*/
struct _GstGLUploadElement
{
/* <private> */
GstGLBaseFilter parent;
GstGLUpload *upload;
GstCaps *in_caps;
GstCaps *out_caps;
};
/**
* GstGLUploadElementClass:
*
* The #GstGLUploadElementClass struct only contains private data
*/
struct _GstGLUploadElementClass
{
GstGLBaseFilterClass object_class;
};
G_END_DECLS
#endif /* __GST_GL_UPLOAD_ELEMENT_H__ */

View file

@ -1,529 +0,0 @@
/*
* GStreamer
* Copyright (C) 2016 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glvideo_flip
* @title: glvideo_flip
*
* Transforms video on the GPU.
*
* ## Examples
* |[
* gst-launch-1.0 videotestsrc ! glupload ! glvideoflip method=clockwise ! glimagesinkelement
* ]| This pipeline flips the test image 90 degrees clockwise.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglvideoflip.h"
#define GST_CAT_DEFAULT gst_gl_video_flip_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define DEFAULT_METHOD GST_GL_VIDEO_FLIP_METHOD_IDENTITY
enum
{
PROP_0,
PROP_METHOD,
PROP_VIDEO_DIRECTION
};
static GstStaticPadTemplate _sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), "
"format = (string) RGBA, "
"width = " GST_VIDEO_SIZE_RANGE ", "
"height = " GST_VIDEO_SIZE_RANGE ", "
"framerate = " GST_VIDEO_FPS_RANGE ", "
"texture-target = (string) 2D"));
static GstStaticPadTemplate _src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), "
"format = (string) RGBA, "
"width = " GST_VIDEO_SIZE_RANGE ", "
"height = " GST_VIDEO_SIZE_RANGE ", "
"framerate = " GST_VIDEO_FPS_RANGE ", "
"texture-target = (string) 2D"));
#define GST_TYPE_GL_VIDEO_FLIP_METHOD (gst_video_flip_method_get_type())
static const GEnumValue video_flip_methods[] = {
{GST_GL_VIDEO_FLIP_METHOD_IDENTITY, "Identity (no rotation)", "none"},
{GST_GL_VIDEO_FLIP_METHOD_90R, "Rotate clockwise 90 degrees", "clockwise"},
{GST_GL_VIDEO_FLIP_METHOD_180, "Rotate 180 degrees", "rotate-180"},
{GST_GL_VIDEO_FLIP_METHOD_90L, "Rotate counter-clockwise 90 degrees",
"counterclockwise"},
{GST_GL_VIDEO_FLIP_METHOD_FLIP_HORIZ, "Flip horizontally", "horizontal-flip"},
{GST_GL_VIDEO_FLIP_METHOD_FLIP_VERT, "Flip vertically", "vertical-flip"},
{GST_GL_VIDEO_FLIP_METHOD_FLIP_UL_LR,
"Flip across upper left/lower right diagonal", "upper-left-diagonal"},
{GST_GL_VIDEO_FLIP_METHOD_FLIP_UR_LL,
"Flip across upper right/lower left diagonal", "upper-right-diagonal"},
{GST_GL_VIDEO_FLIP_METHOD_AUTO,
"Select flip method based on image-orientation tag", "automatic"},
{0, NULL, NULL},
};
static GType
gst_video_flip_method_get_type (void)
{
static GType video_flip_method_type = 0;
if (!video_flip_method_type) {
video_flip_method_type = g_enum_register_static ("GstGLVideoFlipMethod",
video_flip_methods);
}
return video_flip_method_type;
}
static void gst_gl_video_flip_finalize (GObject * object);
static void gst_gl_video_flip_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_video_flip_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstPadProbeReturn _input_sink_probe (GstPad * pad,
GstPadProbeInfo * info, gpointer user_data);
static GstPadProbeReturn _trans_src_probe (GstPad * pad, GstPadProbeInfo * info,
gpointer user_data);
static void
gst_gl_video_flip_video_direction_interface_init (GstVideoDirectionInterface
* iface);
#define gst_gl_video_flip_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstGLVideoFlip, gst_gl_video_flip,
GST_TYPE_BIN, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT,
"glvideoflip", 0, "glvideoflip element");
G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_DIRECTION,
gst_gl_video_flip_video_direction_interface_init););
static void
gst_gl_video_flip_video_direction_interface_init (GstVideoDirectionInterface
* iface)
{
/* We implement the video-direction property */
}
static void
gst_gl_video_flip_class_init (GstGLVideoFlipClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->finalize = gst_gl_video_flip_finalize;
gobject_class->set_property = gst_gl_video_flip_set_property;
gobject_class->get_property = gst_gl_video_flip_get_property;
g_object_class_install_property (gobject_class, PROP_METHOD,
g_param_spec_enum ("method", "method",
"method (deprecated, use video-direction instead)",
GST_TYPE_GL_VIDEO_FLIP_METHOD, DEFAULT_METHOD,
GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
g_object_class_override_property (gobject_class, PROP_VIDEO_DIRECTION,
"video-direction");
gst_element_class_add_static_pad_template (element_class, &_src_template);
gst_element_class_add_static_pad_template (element_class, &_sink_template);
gst_element_class_set_metadata (element_class, "OpenGL video flip filter",
"Filter/Effect/Video", "Flip video on the GPU",
"Matthew Waters <matthew@centricular.com>");
}
static void
gst_gl_video_flip_init (GstGLVideoFlip * flip)
{
gboolean res = TRUE;
GstPad *pad;
flip->aspect = 1.0;
flip->input_capsfilter = gst_element_factory_make ("capsfilter", NULL);
res &= gst_bin_add (GST_BIN (flip), flip->input_capsfilter);
flip->transformation = gst_element_factory_make ("gltransformation", NULL);
g_object_set (flip->transformation, "ortho", TRUE, NULL);
res &= gst_bin_add (GST_BIN (flip), flip->transformation);
flip->output_capsfilter = gst_element_factory_make ("capsfilter", NULL);
res &= gst_bin_add (GST_BIN (flip), flip->output_capsfilter);
res &=
gst_element_link_pads (flip->input_capsfilter, "src",
flip->transformation, "sink");
res &=
gst_element_link_pads (flip->transformation, "src",
flip->output_capsfilter, "sink");
pad = gst_element_get_static_pad (flip->input_capsfilter, "sink");
if (!pad) {
res = FALSE;
} else {
GST_DEBUG_OBJECT (flip, "setting target sink pad %" GST_PTR_FORMAT, pad);
flip->sinkpad = gst_ghost_pad_new ("sink", pad);
flip->sink_probe = gst_pad_add_probe (flip->sinkpad,
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM,
(GstPadProbeCallback) _input_sink_probe, flip, NULL);
gst_element_add_pad (GST_ELEMENT_CAST (flip), flip->sinkpad);
gst_object_unref (pad);
}
pad = gst_element_get_static_pad (flip->transformation, "src");
flip->src_probe = gst_pad_add_probe (pad,
GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM,
(GstPadProbeCallback) _trans_src_probe, flip, NULL);
gst_object_unref (pad);
pad = gst_element_get_static_pad (flip->output_capsfilter, "src");
if (!pad) {
res = FALSE;
} else {
GST_DEBUG_OBJECT (flip, "setting target sink pad %" GST_PTR_FORMAT, pad);
flip->srcpad = gst_ghost_pad_new ("src", pad);
gst_element_add_pad (GST_ELEMENT_CAST (flip), flip->srcpad);
gst_object_unref (pad);
}
if (!res) {
GST_WARNING_OBJECT (flip, "Failed to add/connect the necessary machinery");
}
}
static void
gst_gl_video_flip_finalize (GObject * object)
{
GstGLVideoFlip *flip = GST_GL_VIDEO_FLIP (object);
gst_caps_replace (&flip->input_caps, NULL);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
/* Caps negotiation happens like this:
*
* 1. caps/accept-caps queries bypass the capsfilters on either side of the
* transformation element so the fixed caps don't get in the way.
* 2. Receiving a caps event on the sink pad will set fixed caps on either side
* of the transformation element.
*/
static GstCaps *
_transform_caps (GstGLVideoFlip * vf, GstPadDirection direction, GstCaps * caps)
{
GstCaps *output = gst_caps_copy (caps);
gint i;
for (i = 0; i < gst_caps_get_size (output); i++) {
GstStructure *structure = gst_caps_get_structure (output, i);
gint width, height;
gint par_n, par_d;
if (gst_structure_get_int (structure, "width", &width) &&
gst_structure_get_int (structure, "height", &height)) {
switch (vf->active_method) {
case GST_VIDEO_ORIENTATION_90R:
case GST_VIDEO_ORIENTATION_90L:
case GST_VIDEO_ORIENTATION_UL_LR:
case GST_VIDEO_ORIENTATION_UR_LL:
gst_structure_set (structure, "width", G_TYPE_INT, height,
"height", G_TYPE_INT, width, NULL);
if (gst_structure_get_fraction (structure, "pixel-aspect-ratio",
&par_n, &par_d)) {
if (par_n != 1 || par_d != 1) {
GValue val = { 0, };
g_value_init (&val, GST_TYPE_FRACTION);
gst_value_set_fraction (&val, par_d, par_n);
gst_structure_set_value (structure, "pixel-aspect-ratio", &val);
g_value_unset (&val);
}
}
break;
case GST_VIDEO_ORIENTATION_IDENTITY:
case GST_VIDEO_ORIENTATION_180:
case GST_VIDEO_ORIENTATION_HORIZ:
case GST_VIDEO_ORIENTATION_VERT:
break;
default:
g_assert_not_reached ();
break;
}
}
}
return output;
}
/* with object lock */
static void
_set_active_method (GstGLVideoFlip * vf, GstVideoOrientationMethod method,
GstCaps * caps)
{
gfloat rot_z = 0., scale_x = 1.0, scale_y = 1.0;
GstCaps *output_caps, *templ;
GstPad *srcpad;
switch (method) {
case GST_VIDEO_ORIENTATION_IDENTITY:
break;
case GST_VIDEO_ORIENTATION_90R:
scale_x *= vf->aspect;
scale_y *= 1. / vf->aspect;
rot_z = 90.;
break;
case GST_VIDEO_ORIENTATION_180:
rot_z = 180.;
break;
case GST_VIDEO_ORIENTATION_90L:
scale_x *= vf->aspect;
scale_y *= 1. / vf->aspect;
rot_z = 270.;
break;
case GST_VIDEO_ORIENTATION_HORIZ:
scale_x *= -1.;
break;
case GST_VIDEO_ORIENTATION_UR_LL:
scale_x *= -vf->aspect;
scale_y *= 1. / vf->aspect;
rot_z = 90.;
break;
case GST_VIDEO_ORIENTATION_VERT:
scale_x *= -1.;
rot_z = 180.;
break;
case GST_VIDEO_ORIENTATION_UL_LR:
scale_x *= -vf->aspect;
scale_y *= 1. / vf->aspect;
rot_z = 270.;
break;
default:
break;
}
vf->active_method = method;
output_caps = _transform_caps (vf, GST_PAD_SINK, caps);
gst_caps_replace (&vf->input_caps, caps);
srcpad = gst_element_get_static_pad (vf->transformation, "src");
templ = gst_pad_get_pad_template_caps (srcpad);
gst_object_unref (srcpad);
gst_caps_append (output_caps, gst_caps_ref (templ));
GST_OBJECT_UNLOCK (vf);
g_object_set (vf->input_capsfilter, "caps", gst_caps_ref (caps), NULL);
g_object_set (vf->output_capsfilter, "caps", output_caps, NULL);
g_object_set (vf->transformation, "rotation-z", rot_z, "scale-x", scale_x,
"scale-y", scale_y, NULL);
GST_OBJECT_LOCK (vf);
}
static void
gst_gl_video_flip_set_method (GstGLVideoFlip * vf,
GstVideoOrientationMethod method, gboolean from_tag)
{
GST_OBJECT_LOCK (vf);
if (method == GST_VIDEO_ORIENTATION_CUSTOM) {
GST_WARNING_OBJECT (vf, "unsupported custom orientation");
GST_OBJECT_UNLOCK (vf);
return;
}
/* Store updated method */
if (from_tag)
vf->tag_method = method;
else
vf->method = method;
/* Get the new method */
if (vf->method == GST_VIDEO_ORIENTATION_AUTO)
method = vf->tag_method;
else
method = vf->method;
if (vf->input_caps)
_set_active_method (vf, method, vf->input_caps);
else {
/* just store the configured method here. The actual transform configuration
* will be done once caps are configured. See caps handling in
* _input_sink_probe. */
vf->active_method = method;
}
GST_OBJECT_UNLOCK (vf);
}
static void
gst_gl_video_flip_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLVideoFlip *vf = GST_GL_VIDEO_FLIP (object);
switch (prop_id) {
case PROP_METHOD:
case PROP_VIDEO_DIRECTION:
gst_gl_video_flip_set_method (vf, g_value_get_enum (value), FALSE);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_video_flip_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLVideoFlip *vf = GST_GL_VIDEO_FLIP (object);
switch (prop_id) {
case PROP_METHOD:
case PROP_VIDEO_DIRECTION:
g_value_set_enum (value, vf->method);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstPadProbeReturn
_input_sink_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
GstGLVideoFlip *vf = GST_GL_VIDEO_FLIP (user_data);
if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) {
GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_TAG:{
GstTagList *taglist;
gchar *orientation;
gst_event_parse_tag (event, &taglist);
if (gst_tag_list_get_string (taglist, "image-orientation",
&orientation)) {
if (!g_strcmp0 ("rotate-0", orientation))
gst_gl_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_IDENTITY,
TRUE);
else if (!g_strcmp0 ("rotate-90", orientation))
gst_gl_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_90R, TRUE);
else if (!g_strcmp0 ("rotate-180", orientation))
gst_gl_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_180, TRUE);
else if (!g_strcmp0 ("rotate-270", orientation))
gst_gl_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_90L, TRUE);
else if (!g_strcmp0 ("flip-rotate-0", orientation))
gst_gl_video_flip_set_method (vf,
GST_VIDEO_ORIENTATION_HORIZ, TRUE);
else if (!g_strcmp0 ("flip-rotate-90", orientation))
gst_gl_video_flip_set_method (vf,
GST_VIDEO_ORIENTATION_UR_LL, TRUE);
else if (!g_strcmp0 ("flip-rotate-180", orientation))
gst_gl_video_flip_set_method (vf, GST_VIDEO_ORIENTATION_VERT, TRUE);
else if (!g_strcmp0 ("flip-rotate-270", orientation))
gst_gl_video_flip_set_method (vf,
GST_VIDEO_ORIENTATION_UL_LR, TRUE);
g_free (orientation);
}
break;
}
case GST_EVENT_CAPS:{
GstCaps *caps;
GstVideoInfo v_info;
gst_event_parse_caps (event, &caps);
GST_OBJECT_LOCK (vf);
if (gst_video_info_from_caps (&v_info, caps))
vf->aspect =
(gfloat) GST_VIDEO_INFO_WIDTH (&v_info) /
(gfloat) GST_VIDEO_INFO_HEIGHT (&v_info);
else
vf->aspect = 1.0;
_set_active_method (vf, vf->active_method, caps);
GST_OBJECT_UNLOCK (vf);
break;
}
default:
break;
}
} else if (GST_PAD_PROBE_INFO_TYPE (info) &
GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM) {
GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info);
switch (GST_QUERY_TYPE (query)) {
/* bypass the capsfilter */
case GST_QUERY_CAPS:
case GST_QUERY_ACCEPT_CAPS:{
GstPad *pad = gst_element_get_static_pad (vf->transformation, "sink");
if (gst_pad_query (pad, query)) {
gst_object_unref (pad);
return GST_PAD_PROBE_HANDLED;
} else {
gst_object_unref (pad);
return GST_PAD_PROBE_DROP;
}
}
default:
break;
}
}
return GST_PAD_PROBE_OK;
}
static GstPadProbeReturn
_trans_src_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
GstGLVideoFlip *vf = GST_GL_VIDEO_FLIP (user_data);
if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM) {
GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info);
switch (GST_QUERY_TYPE (query)) {
/* bypass the capsfilter */
case GST_QUERY_CAPS:
case GST_QUERY_ACCEPT_CAPS:{
if (gst_pad_peer_query (vf->srcpad, query))
return GST_PAD_PROBE_HANDLED;
else
return GST_PAD_PROBE_DROP;
}
default:
break;
}
}
return GST_PAD_PROBE_OK;
}

View file

@ -1,97 +0,0 @@
/*
* GStreamer
* Copyright (C) 2016 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_VIDEO_FLIP_H_
#define _GST_GL_VIDEO_FLIP_H_
#include <gst/gl/gl.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_VIDEO_FLIP (gst_gl_video_flip_get_type())
#define GST_GL_VIDEO_FLIP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_VIDEO_FLIP,GstGLVideoFlip))
#define GST_IS_GL_VIDEO_FLIP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_VIDEO_FLIP))
#define GST_GL_VIDEO_FLIP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_VIDEO_FLIP,GstGLVideoFlipClass))
#define GST_IS_GL_VIDEO_FLIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_VIDEO_FLIP))
#define GST_GL_VIDEO_FLIP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_VIDEO_FLIP,GstGLVideoFlipClass))
/**
* GstVideoFlipMethod:
* @GST_GL_VIDEO_FLIP_METHOD_IDENTITY: Identity (no rotation)
* @GST_GL_VIDEO_FLIP_METHOD_90R: Rotate clockwise 90 degrees
* @GST_GL_VIDEO_FLIP_METHOD_180: Rotate 180 degrees
* @GST_GL_VIDEO_FLIP_METHOD_90L: Rotate counter-clockwise 90 degrees
* @GST_GL_VIDEO_FLIP_METHOD_FLIP_HORIZ: Flip horizontally
* @GST_GL_VIDEO_FLIP_METHOD_FLIP_VERT: Flip vertically
* @GST_GL_VIDEO_FLIP_METHOD_FLIP_UL_LR: Flip across upper left/lower right diagonal
* @GST_GL_VIDEO_FLIP_METHOD_FLIP_UR_LL: Flip across upper right/lower left diagonal
* @GST_GL_VIDEO_FLIP_METHOD_AUTO: Select flip method based on image-orientation tag
*
* The different flip methods.
*/
typedef enum {
GST_GL_VIDEO_FLIP_METHOD_IDENTITY,
GST_GL_VIDEO_FLIP_METHOD_90R,
GST_GL_VIDEO_FLIP_METHOD_180,
GST_GL_VIDEO_FLIP_METHOD_90L,
GST_GL_VIDEO_FLIP_METHOD_FLIP_HORIZ,
GST_GL_VIDEO_FLIP_METHOD_FLIP_VERT,
GST_GL_VIDEO_FLIP_METHOD_FLIP_UL_LR,
GST_GL_VIDEO_FLIP_METHOD_FLIP_UR_LL,
GST_GL_VIDEO_FLIP_METHOD_AUTO,
} GstGLVideoFlipMethod;
typedef struct _GstGLVideoFlip GstGLVideoFlip;
typedef struct _GstGLVideoFlipClass GstGLVideoFlipClass;
struct _GstGLVideoFlip
{
GstBin bin;
GstPad *srcpad;
GstPad *sinkpad;
GstElement *input_capsfilter;
GstElement *transformation;
GstElement *output_capsfilter;
gulong sink_probe;
gulong src_probe;
GstCaps *input_caps;
/* properties */
GstVideoOrientationMethod method;
GstVideoOrientationMethod tag_method;
GstVideoOrientationMethod active_method;
gfloat aspect;
};
struct _GstGLVideoFlipClass
{
GstBinClass filter_class;
};
GType gst_gl_video_flip_get_type (void);
G_END_DECLS
#endif /* _GST_GL_VIDEO_FLIP_H_ */

View file

@ -1,359 +0,0 @@
/*
* GStreamer
* Copyright (C) 2009 Julien Isorce <julien.isorce@mail.com>
* Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glviewconvert
* @title: glviewconvert
*
* Convert stereoscopic video between different representations using fragment shaders.
*
* The element can use either property settings or caps negotiation to choose the
* input and output formats to process.
*
* ## Examples
* |[
* gst-launch-1.0 videotestsrc ! glupload ! glviewconvert ! glimagesink
* ]| Simple placebo example demonstrating identity passthrough of mono video
* |[
* gst-launch-1.0 videotestsrc pattern=checkers-1 ! glupload ! \
* glviewconvert input-mode-override=side-by-side ! glimagesink -v
* ]| Force re-interpretation of the input checkers pattern as a side-by-side stereoscopic
* image and display in glimagesink.
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/base/gstbasetransform.h>
#include "gstglviewconvert.h"
#define GST_CAT_DEFAULT gst_gl_view_convert_element_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0,
PROP_INPUT_LAYOUT,
PROP_INPUT_FLAGS,
PROP_OUTPUT_LAYOUT,
PROP_OUTPUT_FLAGS,
PROP_OUTPUT_DOWNMIX_MODE
};
#define DEFAULT_DOWNMIX GST_GL_STEREO_DOWNMIX_ANAGLYPH_GREEN_MAGENTA_DUBOIS
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_view_convert_element_debug, "glview_convertelement", 0, "glview_convert element");
G_DEFINE_TYPE_WITH_CODE (GstGLViewConvertElement, gst_gl_view_convert_element,
GST_TYPE_GL_FILTER, DEBUG_INIT);
#define parent_class gst_gl_view_convert_element_parent_class
static void gst_gl_view_convert_dispose (GObject * object);
static void gst_gl_view_convert_element_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_gl_view_convert_element_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static gboolean gst_gl_view_convert_element_stop (GstBaseTransform * bt);
static gboolean
gst_gl_view_convert_element_set_caps (GstGLFilter * filter, GstCaps * incaps,
GstCaps * outcaps);
static GstCaps *gst_gl_view_convert_element_transform_internal_caps (GstGLFilter
* filter, GstPadDirection direction, GstCaps * caps, GstCaps * filter_caps);
static GstCaps *gst_gl_view_convert_element_fixate_caps (GstBaseTransform *
trans, GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
static GstFlowReturn
gst_gl_view_convert_element_submit_input_buffer (GstBaseTransform * trans,
gboolean is_discont, GstBuffer * input);
static GstFlowReturn
gst_gl_view_convert_element_generate_output_buffer (GstBaseTransform * bt,
GstBuffer ** outbuf);
static void
gst_gl_view_convert_element_class_init (GstGLViewConvertElementClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
gobject_class->set_property = gst_gl_view_convert_element_set_property;
gobject_class->get_property = gst_gl_view_convert_element_get_property;
gobject_class->dispose = gst_gl_view_convert_dispose;
gst_element_class_set_metadata (element_class,
"OpenGL Multiview/3D conversion filter", "Filter",
"Convert stereoscopic/multiview video formats",
"Jan Schmidt <jan@centricular.com>\n"
"Matthew Waters <matthew@centricular.com>");
GST_GL_FILTER_CLASS (klass)->set_caps = gst_gl_view_convert_element_set_caps;
GST_GL_FILTER_CLASS (klass)->transform_internal_caps =
gst_gl_view_convert_element_transform_internal_caps;
GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_view_convert_element_stop;
GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps =
gst_gl_view_convert_element_fixate_caps;
GST_BASE_TRANSFORM_CLASS (klass)->submit_input_buffer =
gst_gl_view_convert_element_submit_input_buffer;
GST_BASE_TRANSFORM_CLASS (klass)->generate_output =
gst_gl_view_convert_element_generate_output_buffer;
g_object_class_install_property (gobject_class, PROP_INPUT_LAYOUT,
g_param_spec_enum ("input-mode-override",
"Input Multiview Mode Override",
"Override any input information about multiview layout",
GST_TYPE_VIDEO_MULTIVIEW_FRAME_PACKING,
GST_VIDEO_MULTIVIEW_MODE_NONE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_INPUT_FLAGS,
g_param_spec_flags ("input-flags-override",
"Input Multiview Flags Override",
"Override any input information about multiview layout flags",
GST_TYPE_VIDEO_MULTIVIEW_FLAGS, GST_VIDEO_MULTIVIEW_FLAGS_NONE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_OUTPUT_LAYOUT,
g_param_spec_enum ("output-mode-override",
"Output Multiview Mode Override",
"Override automatic output mode selection for multiview layout",
GST_TYPE_VIDEO_MULTIVIEW_MODE, GST_VIDEO_MULTIVIEW_MODE_NONE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_OUTPUT_FLAGS,
g_param_spec_flags ("output-flags-override",
"Output Multiview Flags Override",
"Override automatic negotiation for output multiview layout flags",
GST_TYPE_VIDEO_MULTIVIEW_FLAGS, GST_VIDEO_MULTIVIEW_FLAGS_NONE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_OUTPUT_DOWNMIX_MODE,
g_param_spec_enum ("downmix-mode", "Mode for mono downmixed output",
"Output anaglyph type to generate when downmixing to mono",
GST_TYPE_GL_STEREO_DOWNMIX_MODE_TYPE, DEFAULT_DOWNMIX,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
gst_gl_view_convert_element_init (GstGLViewConvertElement * convert)
{
convert->viewconvert = gst_gl_view_convert_new ();
}
static void
gst_gl_view_convert_dispose (GObject * object)
{
GstGLViewConvertElement *convert = GST_GL_VIEW_CONVERT_ELEMENT (object);
if (convert->viewconvert) {
gst_object_unref (convert->viewconvert);
convert->viewconvert = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static gboolean
gst_gl_view_convert_element_set_caps (GstGLFilter * filter, GstCaps * incaps,
GstCaps * outcaps)
{
GstGLViewConvertElement *viewconvert_filter =
GST_GL_VIEW_CONVERT_ELEMENT (filter);
GstCapsFeatures *gl_features;
gboolean ret;
GST_DEBUG_OBJECT (filter, "incaps %" GST_PTR_FORMAT
" outcaps %" GST_PTR_FORMAT, incaps, outcaps);
/* The view_convert component needs RGBA caps */
incaps = gst_caps_copy (incaps);
outcaps = gst_caps_copy (outcaps);
gst_caps_set_simple (incaps, "format", G_TYPE_STRING, "RGBA", NULL);
gl_features =
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
gst_caps_set_features (incaps, 0, gl_features);
gst_caps_set_simple (outcaps, "format", G_TYPE_STRING, "RGBA", NULL);
gl_features =
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
gst_caps_set_features (outcaps, 0, gl_features);
ret = gst_gl_view_convert_set_caps (viewconvert_filter->viewconvert,
incaps, outcaps);
gst_caps_unref (incaps);
gst_caps_unref (outcaps);
return ret;
}
static GstCaps *
gst_gl_view_convert_element_transform_internal_caps (GstGLFilter * filter,
GstPadDirection direction, GstCaps * caps, GstCaps * filter_caps)
{
GstGLViewConvertElement *viewconvert_filter =
GST_GL_VIEW_CONVERT_ELEMENT (filter);
GstCaps *result;
GST_DEBUG_OBJECT (filter, "dir %s transforming caps: %" GST_PTR_FORMAT,
direction == GST_PAD_SINK ? "sink" : "src", caps);
result =
gst_gl_view_convert_transform_caps (viewconvert_filter->viewconvert,
direction, caps, NULL);
GST_DEBUG_OBJECT (filter, "returning caps: %" GST_PTR_FORMAT, result);
return result;
}
static GstCaps *
gst_gl_view_convert_element_fixate_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
{
GstGLViewConvertElement *viewconvert_filter =
GST_GL_VIEW_CONVERT_ELEMENT (trans);
othercaps = gst_gl_view_convert_fixate_caps (viewconvert_filter->viewconvert,
direction, caps, othercaps);
if (gst_caps_is_empty (othercaps))
return othercaps;
/* Let GLfilter do the rest */
return
GST_BASE_TRANSFORM_CLASS
(gst_gl_view_convert_element_parent_class)->fixate_caps (trans, direction,
caps, othercaps);
}
static gboolean
gst_gl_view_convert_element_stop (GstBaseTransform * bt)
{
GstGLViewConvertElement *viewconvert_filter =
GST_GL_VIEW_CONVERT_ELEMENT (bt);
gst_gl_view_convert_reset (viewconvert_filter->viewconvert);
return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (bt);
}
static void
gst_gl_view_convert_element_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLViewConvertElement *convert = GST_GL_VIEW_CONVERT_ELEMENT (object);
switch (prop_id) {
case PROP_INPUT_LAYOUT:
case PROP_INPUT_FLAGS:
g_object_set_property (G_OBJECT (convert->viewconvert), pspec->name,
value);
gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (convert));
break;
case PROP_OUTPUT_LAYOUT:
case PROP_OUTPUT_FLAGS:
g_object_set_property (G_OBJECT (convert->viewconvert), pspec->name,
value);
gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (convert));
break;
case PROP_OUTPUT_DOWNMIX_MODE:
g_object_set_property (G_OBJECT (convert->viewconvert), pspec->name,
value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_view_convert_element_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLViewConvertElement *convert = GST_GL_VIEW_CONVERT_ELEMENT (object);
switch (prop_id) {
case PROP_INPUT_LAYOUT:
case PROP_INPUT_FLAGS:
case PROP_OUTPUT_LAYOUT:
case PROP_OUTPUT_FLAGS:
case PROP_OUTPUT_DOWNMIX_MODE:
g_object_get_property (G_OBJECT (convert->viewconvert), pspec->name,
value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstFlowReturn
gst_gl_view_convert_element_submit_input_buffer (GstBaseTransform * trans,
gboolean is_discont, GstBuffer * input)
{
GstGLContext *context = GST_GL_BASE_FILTER (trans)->context;
GstGLViewConvertElement *viewconvert_filter =
GST_GL_VIEW_CONVERT_ELEMENT (trans);
GstFlowReturn ret;
ret =
GST_BASE_TRANSFORM_CLASS (parent_class)->submit_input_buffer (trans,
is_discont, input);
if (ret != GST_FLOW_OK || trans->queued_buf == NULL)
return ret;
gst_gl_view_convert_set_context (viewconvert_filter->viewconvert, context);
/* Takes the ref to the input buffer */
ret =
gst_gl_view_convert_submit_input_buffer (viewconvert_filter->viewconvert,
is_discont, input);
trans->queued_buf = NULL;
return ret;
}
static GstFlowReturn
gst_gl_view_convert_element_generate_output_buffer (GstBaseTransform * bt,
GstBuffer ** outbuf_ptr)
{
GstGLFilter *filter = GST_GL_FILTER (bt);
GstGLViewConvertElement *viewconvert_filter =
GST_GL_VIEW_CONVERT_ELEMENT (bt);
GstFlowReturn ret = GST_FLOW_OK;
ret = gst_gl_view_convert_get_output (viewconvert_filter->viewconvert,
outbuf_ptr);
if (ret != GST_FLOW_OK) {
GST_ELEMENT_ERROR (filter, RESOURCE, SETTINGS,
("failed to perform view conversion on input buffer"), (NULL));
return ret;
}
return ret;
}

View file

@ -1,53 +0,0 @@
/*
* GStreamer
* Copyright (C) 2014 Jan Schmidt <jan@centricular.com>
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_VIEW_CONVERT_ELEMENT_H_
#define _GST_GL_VIEW_CONVERT_ELEMENT_H_
#include <gst/gl/gstglfilter.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_VIEW_CONVERT_ELEMENT (gst_gl_view_convert_element_get_type())
#define GST_GL_VIEW_CONVERT_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_VIEW_CONVERT_ELEMENT,GstGLViewConvertElement))
#define GST_IS_GL_VIEW_CONVERT_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_VIEW_CONVERT_ELEMENT))
#define GST_GL_VIEW_CONVERT_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_VIEW_CONVERT_ELEMENT,GstGLViewConvertElementClass))
#define GST_IS_GL_VIEW_CONVERT_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_VIEW_CONVERT_ELEMENT))
#define GST_GL_VIEW_CONVERT_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_VIEW_CONVERT_ELEMENT,GstGLViewConvertElementClass))
typedef struct _GstGLViewConvertElement GstGLViewConvertElement;
typedef struct _GstGLViewConvertElementClass GstGLViewConvertElementClass;
struct _GstGLViewConvertElement
{
GstGLFilter filter;
GstGLViewConvert *viewconvert;
};
struct _GstGLViewConvertElementClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_view_convert_element_get_type (void);
G_END_DECLS
#endif /* _GST_GL_VIEW_CONVERT_H_ */

View file

@ -22,14 +22,15 @@
*/
/**
* SECTION:plugin-opengl
* @title: GstOpengl
* SECTION:plugin-openglmixers
* @title: OpenGL Mixers
*
* Cross-platform OpenGL plugin.
* Cross-platform OpenGL mixer plugin.
*
* ## Debugging
*
* ## Examples
* FIXME: update with a mixer example
* |[
* gst-launch-1.0 --gst-debug=gldisplay:3 videotestsrc ! glimagesink
* ]| A debugging pipeline.
@ -43,53 +44,14 @@
#include "config.h"
#endif
#include "gstglimagesink.h"
#include "gstgluploadelement.h"
#include "gstgldownloadelement.h"
#include "gstglcolorconvertelement.h"
#include "gstglcolorbalance.h"
#include "gstglfilterbin.h"
#include "gstglsinkbin.h"
#include "gstglsrcbin.h"
#include "gstglmixerbin.h"
#include "gstglfiltercube.h"
#include "gstgleffects.h"
#include "gstglcolorscale.h"
#include "gstglvideomixer.h"
#include "gstglfiltershader.h"
#include "gstglfilterapp.h"
#include "gstglstereosplit.h"
#include "gstglstereomix.h"
#include "gstglviewconvert.h"
#include "gstgltestsrc.h"
#include "gstgldeinterlace.h"
#if HAVE_GRAPHENE
#include "gstgltransformation.h"
#include "gstglvideoflip.h"
#endif
#if HAVE_JPEG
#if HAVE_PNG
#include "gstgloverlay.h"
#endif /* HAVE_PNG */
#endif /* HAVE_JPEG */
#if GST_GL_HAVE_OPENGL
#include "gstglfilterglass.h"
/* #include "gstglfilterreflectedscreen.h" */
#include "gstglmosaic.h"
#if HAVE_PNG
#include "gstgldifferencematte.h"
/* #include "gstglbumper.h" */
#endif /* HAVE_PNG */
#endif /* GST_GL_HAVE_OPENGL */
#if GST_GL_HAVE_WINDOW_COCOA
/* avoid including Cocoa/CoreFoundation from a C file... */
extern GType gst_ca_opengl_layer_sink_bin_get_type (void);
#endif
#if GST_GL_HAVE_WINDOW_DISPMANX
extern void bcm_host_init (void);
#endif
@ -98,14 +60,13 @@ extern void bcm_host_init (void);
#include <X11/Xlib.h>
#endif
#define GST_CAT_DEFAULT gst_gl_gstgl_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
GST_DEBUG_CATEGORY_STATIC (glmixers_debug);
#define GST_CAT_DEFAULT glmixers_debug
/* 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");
GST_DEBUG_CATEGORY_INIT (glmixers_debug, "openglmixers", 0, "OpenGL Mixers");
#if GST_GL_HAVE_WINDOW_DISPMANX
GST_DEBUG ("Initialize BCM host");
@ -117,81 +78,10 @@ plugin_init (GstPlugin * plugin)
XInitThreads ();
#endif
if (!gst_element_register (plugin, "glimagesink",
GST_RANK_SECONDARY, gst_gl_image_sink_bin_get_type ())) {
return FALSE;
}
if (!gst_element_register (plugin, "glimagesinkelement",
GST_RANK_NONE, gst_glimage_sink_get_type ())) {
return FALSE;
}
if (!gst_element_register (plugin, "glupload",
GST_RANK_NONE, GST_TYPE_GL_UPLOAD_ELEMENT)) {
return FALSE;
}
if (!gst_element_register (plugin, "gldownload",
GST_RANK_NONE, GST_TYPE_GL_DOWNLOAD_ELEMENT)) {
return FALSE;
}
if (!gst_element_register (plugin, "glcolorconvert",
GST_RANK_NONE, GST_TYPE_GL_COLOR_CONVERT_ELEMENT)) {
return FALSE;
}
if (!gst_element_register (plugin, "glcolorbalance",
GST_RANK_NONE, GST_TYPE_GL_COLOR_BALANCE)) {
return FALSE;
}
if (!gst_element_register (plugin, "glfilterbin",
GST_RANK_NONE, GST_TYPE_GL_FILTER_BIN)) {
return FALSE;
}
if (!gst_element_register (plugin, "glsinkbin",
GST_RANK_NONE, GST_TYPE_GL_SINK_BIN)) {
return FALSE;
}
if (!gst_element_register (plugin, "glsrcbin",
GST_RANK_NONE, GST_TYPE_GL_SRC_BIN)) {
return FALSE;
}
if (!gst_element_register (plugin, "glmixerbin",
GST_RANK_NONE, GST_TYPE_GL_MIXER_BIN)) {
return FALSE;
}
if (!gst_element_register (plugin, "glfiltercube",
GST_RANK_NONE, GST_TYPE_GL_FILTER_CUBE)) {
return FALSE;
}
#if HAVE_GRAPHENE
if (!gst_element_register (plugin, "gltransformation",
GST_RANK_NONE, GST_TYPE_GL_TRANSFORMATION)) {
return FALSE;
}
if (!gst_element_register (plugin, "glvideoflip",
GST_RANK_NONE, GST_TYPE_GL_VIDEO_FLIP)) {
return FALSE;
}
#endif
if (!gst_gl_effects_register_filters (plugin, GST_RANK_NONE)) {
return FALSE;
};
if (!gst_element_register (plugin, "glcolorscale",
GST_RANK_NONE, GST_TYPE_GL_COLORSCALE)) {
return FALSE;
}
if (!gst_element_register (plugin, "glvideomixer",
GST_RANK_NONE, gst_gl_video_mixer_bin_get_type ())) {
return FALSE;
@ -201,89 +91,22 @@ plugin_init (GstPlugin * plugin)
GST_RANK_NONE, gst_gl_video_mixer_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, "glfilterapp",
GST_RANK_NONE, GST_TYPE_GL_FILTER_APP)) {
return FALSE;
}
if (!gst_element_register (plugin, "glviewconvert",
GST_RANK_NONE, GST_TYPE_GL_VIEW_CONVERT_ELEMENT)) {
return FALSE;
}
if (!gst_element_register (plugin, "glstereosplit",
GST_RANK_NONE, GST_TYPE_GL_STEREOSPLIT)) {
return FALSE;
}
if (!gst_element_register (plugin, "glstereomix",
GST_RANK_NONE, GST_TYPE_GL_STEREO_MIX)) {
return FALSE;
}
if (!gst_element_register (plugin, "gltestsrc",
GST_RANK_NONE, GST_TYPE_GL_TEST_SRC)) {
return FALSE;
}
if (!gst_element_register (plugin, "gldeinterlace",
GST_RANK_NONE, GST_TYPE_GL_DEINTERLACE)) {
return FALSE;
}
#if HAVE_JPEG
#if HAVE_PNG
if (!gst_element_register (plugin, "gloverlay",
GST_RANK_NONE, gst_gl_overlay_get_type ())) {
return FALSE;
}
#endif /* HAVE_PNG */
#endif /* HAVE_JPEG */
#if GST_GL_HAVE_OPENGL
if (!gst_element_register (plugin, "glfilterglass",
GST_RANK_NONE, GST_TYPE_GL_FILTER_GLASS)) {
return FALSE;
}
#if 0
if (!gst_element_register (plugin, "glfilterreflectedscreen",
GST_RANK_NONE, GST_TYPE_GL_FILTER_REFLECTED_SCREEN)) {
return FALSE;
}
#endif
if (!gst_element_register (plugin, "glmosaic",
GST_RANK_NONE, GST_TYPE_GL_MOSAIC)) {
return FALSE;
}
#if HAVE_PNG
if (!gst_element_register (plugin, "gldifferencematte",
GST_RANK_NONE, gst_gl_differencematte_get_type ())) {
return FALSE;
}
#if 0
if (!gst_element_register (plugin, "glbumper",
GST_RANK_NONE, gst_gl_bumper_get_type ())) {
return FALSE;
}
#endif
#endif /* HAVE_PNG */
#endif /* GST_GL_HAVE_OPENGL */
#if GST_GL_HAVE_WINDOW_COCOA
if (!gst_element_register (plugin, "caopengllayersink",
GST_RANK_NONE, gst_ca_opengl_layer_sink_bin_get_type ())) {
return FALSE;
}
#endif
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
opengl,
"OpenGL plugin",
openglmixers,
"OpenGL mixers",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,98 +1,22 @@
opengl_sources = [
'gstopengl.c',
'gstglbasemixer.c',
'gstgluploadelement.c',
'gstgldownloadelement.c',
'gstglcolorconvertelement.c',
'gstglfilterbin.c',
'gstglmixerbin.c',
'gstglsinkbin.c',
'gstglsrcbin.c',
'gstglimagesink.c',
'gstglfiltercube.c',
'gstgleffects.c',
'effects/gstgleffectscurves.c',
'effects/gstgleffectssources.c',
'effects/gstgleffectidentity.c',
'effects/gstgleffectmirror.c',
'effects/gstgleffectsqueeze.c',
'effects/gstgleffectstretch.c',
'effects/gstgleffectfisheye.c',
'effects/gstgleffecttwirl.c',
'effects/gstgleffectbulge.c',
'effects/gstgleffecttunnel.c',
'effects/gstgleffectsquare.c',
'effects/gstgleffectlumatocurve.c',
'effects/gstgleffectrgbtocurve.c',
'effects/gstgleffectsin.c',
'effects/gstgleffectxray.c',
'effects/gstgleffectglow.c',
'effects/gstgleffectblur.c',
'effects/gstgleffectsobel.c',
'effects/gstgleffectlaplacian.c',
'gstglcolorscale.c',
'gstglcolorbalance.c',
'gstglmixer.c',
'gstglvideomixer.c',
'gstglfiltershader.c',
'gstglfilterapp.c',
'gstglviewconvert.c',
'gstglstereosplit.c',
'gstgldeinterlace.c',
'gstglstereomix.c',
'gltestsrc.c',
'gstgltestsrc.c',
'gstglutils.c'
]
if build_gstgl and gstgl_dep.found()
optional_deps = []
opengl_defines = ['-DGST_USE_UNSTABLE_API']
opengl_defines = []
if gl_dep.found() # have desktop GL
opengl_sources += [
'gstglfilterglass.c',
'gstglmosaic.c',
]
endif
graphene_dep = dependency('graphene-1.0', version : '>=1.4.0', required : false)
if graphene_dep.found()
optional_deps += graphene_dep
opengl_defines += '-DHAVE_GRAPHENE=1'
opengl_sources += [
'gstgltransformation.c',
'gstglvideoflip.c',
]
endif
png_dep = dependency('libpng', version : '>=1.0', required : false)
jpeg_dep = cc.find_library('jpeg-mmx', required : false)
if not jpeg_dep.found()
jpeg_dep = cc.find_library('jpeg', required : false)
endif
if png_dep.found()
optional_deps += png_dep
opengl_defines += '-DHAVE_PNG=1'
opengl_sources += [
'gstgldifferencematte.c',
]
if jpeg_dep.found()
optional_deps += jpeg_dep
opengl_defines += '-DHAVE_JPEG=1'
opengl_sources += [
'gstgloverlay.c',
]
endif
endif
if false # have cocoa
opengl_sources += [
'caopengllayersink.m',
]
endif
if x11_dep.found()
# for XInitThreads()
optional_deps += x11_dep
@ -106,12 +30,12 @@ if build_gstgl and gstgl_dep.found()
optional_deps += gstallocators_dep
endif
gstopengl = library('gstopengl',
gstopenglmixers = library('gstopenglmixers',
opengl_sources,
c_args : gst_plugins_bad_args + opengl_defines,
link_args : noseh_link_args,
include_directories : [configinc],
dependencies : [gstgl_dep, gstbadvideo_dep, gstvideo_dep,
dependencies : [gstbadvideo_dep, gstgl_dep, gstvideo_dep,
gstbase_dep, gstcontroller_dep, libm] + optional_deps,
install : true,
install_dir : plugins_install_dir,