mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-15 18:55:19 +00:00
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:
parent
769a21d0bb
commit
ee589cd337
74 changed files with 42 additions and 19162 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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",
|
||||
};
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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* */
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
1168
ext/gl/gltestsrc.c
1168
ext/gl/gltestsrc.c
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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 (®istered)) {
|
||||
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 (®istered, generic_type);
|
||||
}
|
||||
return registered;
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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 (¢er, 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, ¢er, &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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue