Remove openglmixers plugin, moved to -base

Merged into the existing opengl plugin in -base.
This commit is contained in:
Tim-Philipp Müller 2018-12-27 17:52:47 +01:00
parent e42efbccb1
commit 88683e5a1e
28 changed files with 1 additions and 7075 deletions

View file

@ -2656,7 +2656,6 @@ ext/faad/Makefile
ext/fdkaac/Makefile
ext/flite/Makefile
ext/fluidsynth/Makefile
ext/gl/Makefile
ext/gsm/Makefile
ext/hls/Makefile
ext/iqa/Makefile

View file

@ -113,11 +113,6 @@
<xi:include href="xml/element-gaussianblur.xml" />
<xi:include href="xml/element-gdpdepay.xml" />
<xi:include href="xml/element-gdppay.xml" />
<xi:include href="xml/element-glmixerbin.xml" />
<xi:include href="xml/element-glmosaic.xml" />
<xi:include href="xml/element-glstereomix.xml" />
<xi:include href="xml/element-glvideomixerelement.xml" />
<xi:include href="xml/element-glvideomixer.xml" />
<xi:include href="xml/element-gmedec.xml" />
<xi:include href="xml/element-grabcut.xml" />
<xi:include href="xml/element-gsmdec.xml" />
@ -369,7 +364,6 @@
<xi:include href="xml/plugin-openal.xml" />
<xi:include href="xml/plugin-opencv.xml" />
<xi:include href="xml/plugin-openexr.xml" />
<xi:include href="xml/plugin-openglmixers.xml" />
<xi:include href="xml/plugin-openh264.xml" />
<xi:include href="xml/plugin-openjpeg.xml" />
<xi:include href="xml/plugin-opusparse.xml" />

View file

@ -1554,88 +1554,6 @@ GST_TYPE_GDP_PAY
gst_gdp_pay_get_type
</SECTION>
<SECTION>
<FILE>element-glmixerbin</FILE>
<TITLE>glmixerbin</TITLE>
GstGLMixerBin
GstGLMixerBinStartTimeSelection
<SUBSECTION Standard>
GstGLMixerBinClass
GST_GL_MIXER_BIN
GST_GL_MIXER_BIN_CAST
GST_IS_GL_MIXER_BIN
GST_GL_MIXER_BIN_CLASS
GST_IS_GL_MIXER_BIN_CLASS
GST_TYPE_GL_MIXER_BIN
<SUBSECTION Private>
gst_gl_mixer_bin_get_type
</SECTION>
<SECTION>
<FILE>element-glmosaic</FILE>
<TITLE>glmosaic</TITLE>
GstGLMosaic
<SUBSECTION Standard>
GstGLMosaicClass
GST_GL_MOSAIC
GST_GL_MOSAIC_CAST
GST_IS_GL_MOSAIC
GST_GL_MOSAIC_CLASS
GST_IS_GL_MOSAIC_CLASS
GST_TYPE_GL_MOSAIC
<SUBSECTION Private>
gst_gl_mosaic_get_type
</SECTION>
<SECTION>
<FILE>element-glstereomix</FILE>
<TITLE>glstereomix</TITLE>
GstGLStereoMix
<SUBSECTION Standard>
GstGLStereoMixClass
GST_GL_STEREO_MIX
GST_GL_STEREO_MIX_CAST
GST_IS_GL_STEREO_MIX
GST_GL_STEREO_MIX_CLASS
GST_IS_GL_STEREO_MIX_CLASS
GST_TYPE_GL_STEREO_MIX
<SUBSECTION Private>
gst_gl_stereo_mix_get_type
</SECTION>
<SECTION>
<FILE>element-glvideomixerelement</FILE>
<TITLE>glvideomixerelement</TITLE>
GstGLVideoMixer
GstGLVideoMixerBackground
<SUBSECTION Standard>
GstGLVideoMixerClass
GST_GL_VIDEO_MIXER
GST_GL_VIDEO_MIXER_CAST
GST_IS_GL_VIDEO_MIXER
GST_GL_VIDEO_MIXER_CLASS
GST_IS_GL_VIDEO_MIXER_CLASS
GST_TYPE_GL_VIDEO_MIXER
<SUBSECTION Private>
gst_gl_video_mixer_get_type
</SECTION>
<SECTION>
<FILE>element-glvideomixer</FILE>
<TITLE>glvideomixer</TITLE>
GstGLVideoMixerBin
<SUBSECTION Standard>
GstGLVideoMixerBinClass
GST_GL_VIDEO_MIXER_BIN
GST_GL_VIDEO_MIXER_BIN_CAST
GST_IS_GL_VIDEO_MIXER_BIN
GST_GL_VIDEO_MIXER_BIN_CLASS
GST_IS_GL_VIDEO_MIXER_BIN_CLASS
GST_TYPE_GL_VIDEO_MIXER_BIN
<SUBSECTION Private>
gst_gl_video_mixer_bin_get_type
</SECTION>
<SECTION>
<FILE>element-gsmdec</FILE>
<TITLE>gsmdec</TITLE>

View file

@ -1,118 +0,0 @@
<plugin>
<name>openglmixers</name>
<description>OpenGL mixers</description>
<filename>../../ext/gl/.libs/libgstopenglmixers.so</filename>
<basename>libgstopenglmixers.so</basename>
<version>1.15.0.1</version>
<license>LGPL</license>
<source>gst-plugins-bad</source>
<package>GStreamer Bad Plug-ins git</package>
<origin>Unknown package origin</origin>
<elements>
<element>
<name>glmixerbin</name>
<longname>OpenGL video_mixer empty bin</longname>
<class>Bin/Filter/Effect/Video/Mixer</class>
<description>OpenGL video_mixer empty bin</description>
<author>Matthew Waters &lt;matthew@centricular.com&gt;</author>
<pads>
<caps>
<name>sink_%u</name>
<direction>sink</direction>
<presence>request</presence>
<details>video/x-raw(memory:GLMemory, meta:GstVideoOverlayComposition), format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(memory:DMABuf, meta:GstVideoOverlayComposition), format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(memory:SystemMemory, meta:GstVideoOverlayComposition), format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(meta:GstVideoGLTextureUploadMeta, meta:GstVideoOverlayComposition), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(memory:GLMemory), format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(memory:DMABuf), format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(meta:GstVideoGLTextureUploadMeta), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
</caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>video/x-raw(ANY)</details>
</caps>
</pads>
</element>
<element>
<name>glmosaic</name>
<longname>OpenGL mosaic</longname>
<class>Filter/Effect/Video</class>
<description>OpenGL mosaic</description>
<author>Julien Isorce &lt;julien.isorce@gmail.com&gt;</author>
<pads>
<caps>
<name>sink_%u</name>
<direction>sink</direction>
<presence>request</presence>
<details>video/x-raw(memory:GLMemory), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
</caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>video/x-raw(memory:GLMemory), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
</caps>
</pads>
</element>
<element>
<name>glstereomix</name>
<longname>OpenGL stereo video combiner</longname>
<class>Filter/Effect/Video</class>
<description>OpenGL stereo video combiner</description>
<author>Jan Schmidt &lt;jan@centricular.com&gt;</author>
<pads>
<caps>
<name>sink_%u</name>
<direction>sink</direction>
<presence>request</presence>
<details>video/x-raw(memory:GLMemory), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ], texture-target=(string)2D; video/x-raw(meta:GstVideoGLTextureUploadMeta), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string){ RGBA, RGB, RGBx, BGR, BGRx, BGRA, xRGB, xBGR, ARGB, ABGR, Y444, I420, YV12, Y42B, Y41B, NV12, NV21, YUY2, UYVY, AYUV, GRAY8, GRAY16_LE, GRAY16_BE, RGB16, BGR16, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
</caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>video/x-raw(memory:GLMemory), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ], texture-target=(string)2D; video/x-raw(meta:GstVideoGLTextureUploadMeta), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string){ RGBA, RGB, RGBx, BGR, BGRx, BGRA, xRGB, xBGR, ARGB, ABGR, Y444, I420, YV12, Y42B, Y41B, NV12, NV21, YUY2, UYVY, AYUV, GRAY8, GRAY16_LE, GRAY16_BE, RGB16, BGR16, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
</caps>
</pads>
</element>
<element>
<name>glvideomixer</name>
<longname>OpenGL video_mixer bin</longname>
<class>Bin/Filter/Effect/Video/Compositor</class>
<description>OpenGL video_mixer bin</description>
<author>Matthew Waters &lt;matthew@centricular.com&gt;</author>
<pads>
<caps>
<name>sink_%u</name>
<direction>sink</direction>
<presence>request</presence>
<details>video/x-raw(memory:GLMemory, meta:GstVideoOverlayComposition), format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(memory:DMABuf, meta:GstVideoOverlayComposition), format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(memory:SystemMemory, meta:GstVideoOverlayComposition), format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(meta:GstVideoGLTextureUploadMeta, meta:GstVideoOverlayComposition), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(memory:GLMemory), format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(memory:DMABuf), format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw, format=(string){ RGBA, BGRA, RGBx, BGRx, ARGB, ABGR, xRGB, xBGR, RGB, BGR, RGB16, BGR16, AYUV, I420, YV12, NV12, NV21, YUY2, UYVY, Y41B, Y42B, Y444, GRAY8, GRAY16_LE, GRAY16_BE, ARGB64 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(meta:GstVideoGLTextureUploadMeta), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
</caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>video/x-raw(ANY)</details>
</caps>
</pads>
</element>
<element>
<name>glvideomixerelement</name>
<longname>OpenGL video_mixer</longname>
<class>Filter/Effect/Video/Compositor</class>
<description>OpenGL video_mixer</description>
<author>Matthew Waters &lt;matthew@centricular.com&gt;</author>
<pads>
<caps>
<name>sink_%u</name>
<direction>sink</direction>
<presence>request</presence>
<details>video/x-raw(memory:GLMemory), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
</caps>
<caps>
<name>src</name>
<direction>source</direction>
<presence>always</presence>
<details>video/x-raw(memory:GLMemory), format=(string)RGBA, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
</caps>
</pads>
</element>
</elements>
</plugin>

View file

@ -76,12 +76,6 @@ else
DTS_DIR=
endif
if USE_GL
GL_DIR=gl
else
GL_DIR=
endif
if USE_RESINDVD
RESINDVD_DIR = resindvd
else
@ -418,7 +412,6 @@ SUBDIRS=\
$(WAYLAND_DIR) \
$(DTS_DIR) \
$(RESINDVD_DIR) \
$(GL_DIR) \
$(FAAC_DIR) \
$(FAAD_DIR) \
$(FDK_AAC_DIR) \
@ -497,7 +490,6 @@ DIST_SUBDIRS = \
libmms \
lv2 \
dts \
gl \
modplug \
mpeg2enc \
mplex \

View file

@ -1,54 +0,0 @@
plugin_LTLIBRARIES = libgstopenglmixers.la
# These have to stay in -bad until we can move GstVideoAggregator to -base
libgstopenglmixers_la_SOURCES = \
gstopengl.c \
gstglbasemixer.c \
gstglmixer.c \
gstglmixerbin.c \
gstglstereomix.c \
gstglutils.c \
gstglvideomixer.c
noinst_HEADERS = \
gstglbasemixer.h \
gstglmixer.h \
gstglmixerbin.h \
gstglstereomix.h \
gstglutils.h \
gstglvideomixer.h
# full opengl required
if USE_OPENGL
libgstopenglmixers_la_SOURCES += gstglmosaic.c
noinst_HEADERS += gstglmosaic.h
endif
# 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)?
libgstopenglmixers_la_CFLAGS = \
$(GST_PLUGINS_BAD_CFLAGS) \
$(GST_GL_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_CONTROLLER_CFLAGS) \
$(GST_CFLAGS) \
$(X11_CFLAGS) \
-Dgst_gl_context_gen_shader=gst_gl_bad_context_gen_shader \
-Dgst_gl_multiply_matrix4=Dgst_gl_bad_multiply_matrix4 \
-Dgst_gl_get_affine_transformation_meta_as_ndc_ext=Dgst_gl_bad_get_affine_transformation_meta_as_ndc_ext \
-Dgst_gl_set_affine_transformation_meta_from_ndc_ext=Dgst_gl_bad_set_affine_transformation_meta_from_ndc_ext
libgstopenglmixers_la_LIBADD = \
$(GST_GL_LIBS) \
$(GST_PLUGINS_BASE_LIBS) \
$(GST_BASE_LIBS) \
$(GST_CONTROLLER_LIBS) \
$(GST_LIBS) \
$(X11_LIBS) \
$(LIBM)
libgstopenglmixers_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstopenglmixers_la_LIBTOOLFLAGS = --tag=CC

View file

@ -1,462 +0,0 @@
/* Generic video mixer plugin
*
* 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/gst.h>
#include <gst/video/video.h>
#include "gstglbasemixer.h"
#define GST_CAT_DEFAULT gst_gl_base_mixer_debug
GST_DEBUG_CATEGORY (gst_gl_base_mixer_debug);
static void gst_gl_base_mixer_pad_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_base_mixer_pad_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_base_mixer_set_context (GstElement * element,
GstContext * context);
static GstStateChangeReturn gst_gl_base_mixer_change_state (GstElement *
element, GstStateChange transition);
struct _GstGLBaseMixerPrivate
{
gboolean negotiated;
GstGLContext *other_context;
};
#define gst_gl_base_mixer_parent_class parent_class
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstGLBaseMixer, gst_gl_base_mixer,
GST_TYPE_VIDEO_AGGREGATOR);
G_DEFINE_TYPE (GstGLBaseMixerPad, gst_gl_base_mixer_pad,
GST_TYPE_VIDEO_AGGREGATOR_PAD);
static void
gst_gl_base_mixer_pad_class_init (GstGLBaseMixerPadClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstVideoAggregatorPadClass *vaggpad_class =
(GstVideoAggregatorPadClass *) klass;
gobject_class->set_property = gst_gl_base_mixer_pad_set_property;
gobject_class->get_property = gst_gl_base_mixer_pad_get_property;
vaggpad_class->prepare_frame = NULL;
vaggpad_class->clean_frame = NULL;
}
static void
gst_gl_base_mixer_pad_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_base_mixer_pad_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 gboolean
_find_local_gl_context (GstGLBaseMixer * mix)
{
if (gst_gl_query_local_gl_context (GST_ELEMENT (mix), GST_PAD_SRC,
&mix->context))
return TRUE;
if (gst_gl_query_local_gl_context (GST_ELEMENT (mix), GST_PAD_SINK,
&mix->context))
return TRUE;
return FALSE;
}
static gboolean
_get_gl_context (GstGLBaseMixer * mix)
{
GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
GError *error = NULL;
if (!gst_gl_ensure_element_data (mix, &mix->display,
&mix->priv->other_context))
return FALSE;
gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
_find_local_gl_context (mix);
GST_OBJECT_LOCK (mix->display);
if (!mix->context) {
do {
if (mix->context) {
gst_object_unref (mix->context);
mix->context = NULL;
}
/* just get a GL context. we don't care */
mix->context =
gst_gl_display_get_gl_context_for_thread (mix->display, NULL);
if (!mix->context) {
if (!gst_gl_display_create_context (mix->display,
mix->priv->other_context, &mix->context, &error)) {
GST_OBJECT_UNLOCK (mix->display);
goto context_error;
}
}
} while (!gst_gl_display_add_context (mix->display, mix->context));
}
GST_OBJECT_UNLOCK (mix->display);
{
GstGLAPI current_gl_api = gst_gl_context_get_gl_api (mix->context);
if ((current_gl_api & mix_class->supported_gl_api) == 0)
goto unsupported_gl_api;
}
return TRUE;
unsupported_gl_api:
{
GstGLAPI gl_api = gst_gl_context_get_gl_api (mix->context);
gchar *gl_api_str = gst_gl_api_to_string (gl_api);
gchar *supported_gl_api_str =
gst_gl_api_to_string (mix_class->supported_gl_api);
GST_ELEMENT_ERROR (mix, 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 (mix, RESOURCE, NOT_FOUND, ("%s", error->message),
(NULL));
g_clear_error (&error);
return FALSE;
}
}
static gboolean
gst_gl_base_mixer_propose_allocation (GstAggregator * agg,
GstAggregatorPad * aggpad, GstQuery * decide_query, GstQuery * query)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
if (!_get_gl_context (mix))
return FALSE;
return TRUE;
}
static gboolean
gst_gl_base_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad,
GstQuery * query)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
GST_TRACE ("QUERY %" GST_PTR_FORMAT, query);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
{
if (gst_gl_handle_context_query ((GstElement *) mix, query,
mix->display, mix->context, mix->priv->other_context))
return TRUE;
break;
}
default:
break;
}
return GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query);;
}
static void
gst_gl_base_mixer_pad_init (GstGLBaseMixerPad * mixerpad)
{
}
/* GLBaseMixer signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_CONTEXT
};
static gboolean gst_gl_base_mixer_src_query (GstAggregator * agg,
GstQuery * query);
static gboolean
gst_gl_base_mixer_src_activate_mode (GstAggregator * aggregator,
GstPadMode mode, gboolean active);
static gboolean gst_gl_base_mixer_stop (GstAggregator * agg);
static gboolean gst_gl_base_mixer_start (GstAggregator * agg);
static void gst_gl_base_mixer_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_base_mixer_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_gl_base_mixer_decide_allocation (GstAggregator * agg,
GstQuery * query);
static void
gst_gl_base_mixer_class_init (GstGLBaseMixerClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "opengl mixer");
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->get_property = gst_gl_base_mixer_get_property;
gobject_class->set_property = gst_gl_base_mixer_set_property;
element_class->set_context =
GST_DEBUG_FUNCPTR (gst_gl_base_mixer_set_context);
element_class->change_state = gst_gl_base_mixer_change_state;
agg_class->sink_query = gst_gl_base_mixer_sink_query;
agg_class->src_query = gst_gl_base_mixer_src_query;
agg_class->src_activate = gst_gl_base_mixer_src_activate_mode;
agg_class->stop = gst_gl_base_mixer_stop;
agg_class->start = gst_gl_base_mixer_start;
agg_class->decide_allocation = gst_gl_base_mixer_decide_allocation;
agg_class->propose_allocation = gst_gl_base_mixer_propose_allocation;
g_object_class_install_property (gobject_class, PROP_CONTEXT,
g_param_spec_object ("context",
"OpenGL context",
"Get OpenGL context",
GST_TYPE_GL_CONTEXT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/* Register the pad class */
g_type_class_ref (GST_TYPE_GL_BASE_MIXER_PAD);
klass->supported_gl_api = GST_GL_API_ANY;
}
static void
gst_gl_base_mixer_init (GstGLBaseMixer * mix)
{
mix->priv = gst_gl_base_mixer_get_instance_private (mix);
}
static void
gst_gl_base_mixer_set_context (GstElement * element, GstContext * context)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (element);
GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
gst_gl_handle_set_context (element, context, &mix->display,
&mix->priv->other_context);
if (mix->display)
gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
}
static gboolean
gst_gl_base_mixer_activate (GstGLBaseMixer * mix, gboolean active)
{
GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
gboolean result = TRUE;
if (active) {
if (!gst_gl_ensure_element_data (mix, &mix->display,
&mix->priv->other_context))
return FALSE;
gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
}
return result;
}
static gboolean
gst_gl_base_mixer_src_activate_mode (GstAggregator * aggregator,
GstPadMode mode, gboolean active)
{
GstGLBaseMixer *mix;
gboolean result = FALSE;
mix = GST_GL_BASE_MIXER (aggregator);
switch (mode) {
case GST_PAD_MODE_PUSH:
case GST_PAD_MODE_PULL:
result = gst_gl_base_mixer_activate (mix, active);
break;
default:
result = TRUE;
break;
}
return result;
}
static gboolean
gst_gl_base_mixer_src_query (GstAggregator * agg, GstQuery * query)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
{
if (gst_gl_handle_context_query ((GstElement *) mix, query,
mix->display, mix->context, mix->priv->other_context))
return TRUE;
break;
}
default:
break;
}
return GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
}
static gboolean
gst_gl_base_mixer_decide_allocation (GstAggregator * agg, GstQuery * query)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
if (!_get_gl_context (mix))
return FALSE;
return TRUE;
}
static void
gst_gl_base_mixer_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstGLBaseMixer *mixer = GST_GL_BASE_MIXER (object);
switch (prop_id) {
case PROP_CONTEXT:
g_value_set_object (value, mixer->context);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_base_mixer_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_base_mixer_start (GstAggregator * agg)
{
return GST_AGGREGATOR_CLASS (parent_class)->start (agg);;
}
static gboolean
gst_gl_base_mixer_stop (GstAggregator * agg)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
if (mix->context) {
gst_object_unref (mix->context);
mix->context = NULL;
}
return TRUE;
}
static GstStateChangeReturn
gst_gl_base_mixer_change_state (GstElement * element, GstStateChange transition)
{
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (element);
GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GST_DEBUG_OBJECT (mix, "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, &mix->display,
&mix->priv->other_context))
return GST_STATE_CHANGE_FAILURE;
gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
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 (mix->priv->other_context) {
gst_object_unref (mix->priv->other_context);
mix->priv->other_context = NULL;
}
if (mix->display) {
gst_object_unref (mix->display);
mix->display = NULL;
}
break;
default:
break;
}
return ret;
}

View file

@ -1,98 +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_BASE_MIXER_H__
#define __GST_GL_BASE_MIXER_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
#include <gst/video/gstvideoaggregator.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_BASE_MIXER_PAD (gst_gl_base_mixer_pad_get_type())
#define GST_GL_BASE_MIXER_PAD(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_BASE_MIXER_PAD, GstGLBaseMixerPad))
#define GST_GL_BASE_MIXER_PAD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_BASE_MIXER_PAD, GstGLBaseMixerPadClass))
#define GST_IS_GL_BASE_MIXER_PAD(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_BASE_MIXER_PAD))
#define GST_IS_GL_BASE_MIXER_PAD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_BASE_MIXER_PAD))
#define GST_GL_BASE_MIXER_PAD_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_GL_BASE_MIXER_PAD,GstGLBaseMixerPadClass))
typedef struct _GstGLBaseMixerPad GstGLBaseMixerPad;
typedef struct _GstGLBaseMixerPadClass GstGLBaseMixerPadClass;
/* all information needed for one video stream */
struct _GstGLBaseMixerPad
{
GstVideoAggregatorPad parent; /* subclass the pad */
};
struct _GstGLBaseMixerPadClass
{
GstVideoAggregatorPadClass parent_class;
};
GType gst_gl_base_mixer_pad_get_type (void);
#define GST_TYPE_GL_BASE_MIXER (gst_gl_base_mixer_get_type())
#define GST_GL_BASE_MIXER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_BASE_MIXER, GstGLBaseMixer))
#define GST_GL_BASE_MIXER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_BASE_MIXER, GstGLBaseMixerClass))
#define GST_IS_GL_BASE_MIXER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_BASE_MIXER))
#define GST_IS_GL_BASE_MIXER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_BASE_MIXER))
#define GST_GL_BASE_MIXER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_GL_BASE_MIXER,GstGLBaseMixerClass))
typedef struct _GstGLBaseMixer GstGLBaseMixer;
typedef struct _GstGLBaseMixerClass GstGLBaseMixerClass;
typedef struct _GstGLBaseMixerPrivate GstGLBaseMixerPrivate;
struct _GstGLBaseMixer
{
GstVideoAggregator vaggregator;
GstGLDisplay *display;
GstGLContext *context;
gpointer _padding[GST_PADDING];
GstGLBaseMixerPrivate *priv;
};
struct _GstGLBaseMixerClass
{
GstVideoAggregatorClass parent_class;
GstGLAPI supported_gl_api;
gpointer _padding[GST_PADDING];
};
GType gst_gl_base_mixer_get_type(void);
G_END_DECLS
#endif /* __GST_GL_BASE_MIXER_H__ */

View file

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

View file

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

View file

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

View file

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

View file

@ -1,725 +0,0 @@
/* Generic video mixer plugin
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include <gst/video/video.h>
#include <string.h>
#include "gstglmixer.h"
#define GST_CAT_DEFAULT gst_gl_mixer_debug
GST_DEBUG_CATEGORY (gst_gl_mixer_debug);
static void gst_gl_mixer_pad_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static gboolean gst_gl_mixer_pad_prepare_frame (GstVideoAggregatorPad * vpad,
GstVideoAggregator * vagg, GstBuffer * buffer,
GstVideoFrame * prepared_frame);
static void gst_gl_mixer_pad_clean_frame (GstVideoAggregatorPad * vpad,
GstVideoAggregator * vagg, GstVideoFrame * prepared_frame);
enum
{
PROP_PAD_0
};
struct _GstGLMixerPrivate
{
gboolean negotiated;
gboolean gl_resource_ready;
GMutex gl_resource_lock;
GCond gl_resource_cond;
};
#define gst_gl_mixer_parent_class parent_class
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstGLMixer, gst_gl_mixer,
GST_TYPE_GL_BASE_MIXER);
G_DEFINE_TYPE (GstGLMixerPad, gst_gl_mixer_pad, GST_TYPE_GL_BASE_MIXER_PAD);
static void
gst_gl_mixer_pad_class_init (GstGLMixerPadClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstVideoAggregatorPadClass *vaggpad_class =
(GstVideoAggregatorPadClass *) klass;
gobject_class->set_property = gst_gl_mixer_pad_set_property;
gobject_class->get_property = gst_gl_mixer_pad_get_property;
vaggpad_class->prepare_frame = gst_gl_mixer_pad_prepare_frame;
vaggpad_class->clean_frame = gst_gl_mixer_pad_clean_frame;
}
static void
gst_gl_mixer_pad_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_mixer_pad_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 gboolean
gst_gl_mixer_pad_prepare_frame (GstVideoAggregatorPad * vpad,
GstVideoAggregator * vagg, GstBuffer * buffer,
GstVideoFrame * prepared_frame)
{
GstGLMixerPad *pad = GST_GL_MIXER_PAD (vpad);
GstGLMixer *mix = GST_GL_MIXER (vagg);
GstVideoInfo gl_info;
GstGLSyncMeta *sync_meta;
pad->current_texture = 0;
gst_video_info_set_format (&gl_info,
GST_VIDEO_FORMAT_RGBA,
GST_VIDEO_INFO_WIDTH (&vpad->info), GST_VIDEO_INFO_HEIGHT (&vpad->info));
sync_meta = gst_buffer_get_gl_sync_meta (buffer);
if (sync_meta)
gst_gl_sync_meta_wait (sync_meta, GST_GL_BASE_MIXER (mix)->context);
if (!gst_video_frame_map (prepared_frame, &gl_info, buffer,
GST_MAP_READ | GST_MAP_GL)) {
GST_ERROR_OBJECT (pad, "Failed to map input frame");
return FALSE;
}
pad->current_texture = *(guint *) prepared_frame->data[0];
return TRUE;
}
static void
gst_gl_mixer_pad_clean_frame (GstVideoAggregatorPad * vpad,
GstVideoAggregator * vagg, GstVideoFrame * prepared_frame)
{
GstGLMixerPad *pad = GST_GL_MIXER_PAD (vpad);
pad->current_texture = 0;
if (prepared_frame->buffer) {
gst_video_frame_unmap (prepared_frame);
memset (prepared_frame, 0, sizeof (GstVideoFrame));
}
}
static gboolean
_negotiated_caps (GstAggregator * agg, GstCaps * caps)
{
GstGLMixer *mix = GST_GL_MIXER (agg);
gboolean ret;
mix->priv->negotiated = TRUE;
gst_caps_replace (&mix->out_caps, caps);
ret = GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps);
return ret;
}
static void
_find_best_format (GstVideoAggregator * vagg, GstCaps * downstream_caps,
GstVideoInfo * best_info, gboolean * at_least_one_alpha)
{
GstVideoInfo tmp_info;
GST_VIDEO_AGGREGATOR_CLASS (parent_class)->find_best_format (vagg,
downstream_caps, best_info, at_least_one_alpha);
gst_video_info_set_format (&tmp_info, GST_VIDEO_FORMAT_RGBA,
best_info->width, best_info->height);
tmp_info.par_n = best_info->par_n;
tmp_info.par_d = best_info->par_d;
tmp_info.fps_n = best_info->fps_n;
tmp_info.fps_d = best_info->fps_d;
tmp_info.flags = best_info->flags;
tmp_info.interlace_mode = best_info->interlace_mode;
*best_info = tmp_info;
}
static gboolean
gst_gl_mixer_propose_allocation (GstAggregator * agg,
GstAggregatorPad * agg_pad, GstQuery * decide_query, GstQuery * query)
{
GstGLMixer *mix = GST_GL_MIXER (agg);
GstGLBaseMixer *base_mix = GST_GL_BASE_MIXER (agg);
GstGLContext *context;
GstBufferPool *pool = NULL;
GstStructure *config;
GstCaps *caps;
GstVideoInfo info;
guint size = 0;
gboolean need_pool;
if (!GST_AGGREGATOR_CLASS (gst_gl_mixer_parent_class)->propose_allocation
(agg, agg_pad, decide_query, query))
return FALSE;
context = base_mix->context;
gst_query_parse_allocation (query, &caps, &need_pool);
if (caps == NULL)
goto no_caps;
if (!gst_video_info_from_caps (&info, caps))
goto invalid_caps;
/* the normal size of a frame */
size = info.size;
if (need_pool) {
GST_DEBUG_OBJECT (mix, "create new pool");
pool = gst_gl_buffer_pool_new (context);
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
if (!gst_buffer_pool_set_config (pool, config)) {
g_object_unref (pool);
goto config_failed;
}
}
gst_query_add_allocation_pool (query, pool, size, 1, 0);
if (pool)
g_object_unref (pool);
/* we also support various metadata */
if (context->gl_vtable->FenceSync)
gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
return TRUE;
/* ERRORS */
no_caps:
{
GST_DEBUG_OBJECT (mix, "no caps specified");
return FALSE;
}
invalid_caps:
{
GST_DEBUG_OBJECT (mix, "invalid caps specified");
return FALSE;
}
config_failed:
{
GST_DEBUG_OBJECT (mix, "failed setting config");
return FALSE;
}
}
static gboolean
gst_gl_mixer_pad_sink_acceptcaps (GstPad * pad, GstGLMixer * mix,
GstCaps * caps)
{
gboolean ret;
GstCaps *template_caps;
GST_DEBUG_OBJECT (pad, "try accept caps of %" GST_PTR_FORMAT, caps);
template_caps = gst_pad_get_pad_template_caps (pad);
template_caps = gst_caps_make_writable (template_caps);
ret = gst_caps_can_intersect (caps, template_caps);
GST_DEBUG_OBJECT (pad, "%saccepted caps %" GST_PTR_FORMAT,
(ret ? "" : "not "), caps);
gst_caps_unref (template_caps);
return ret;
}
static GstCaps *
gst_gl_mixer_pad_sink_getcaps (GstPad * pad, GstGLMixer * mix, GstCaps * filter)
{
GstCaps *sinkcaps;
GstCaps *template_caps;
GstCaps *filtered_caps;
GstCaps *returned_caps;
template_caps = gst_pad_get_pad_template_caps (pad);
sinkcaps = gst_pad_get_current_caps (pad);
if (sinkcaps == NULL) {
sinkcaps = gst_caps_ref (template_caps);
} else {
sinkcaps = gst_caps_merge (sinkcaps, gst_caps_ref (template_caps));
}
if (filter) {
filtered_caps = gst_caps_intersect (sinkcaps, filter);
gst_caps_unref (sinkcaps);
} else {
filtered_caps = sinkcaps; /* pass ownership */
}
returned_caps = gst_caps_intersect (filtered_caps, template_caps);
gst_caps_unref (template_caps);
gst_caps_unref (filtered_caps);
GST_DEBUG_OBJECT (pad, "returning %" GST_PTR_FORMAT, returned_caps);
return returned_caps;
}
static gboolean
gst_gl_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad,
GstQuery * query)
{
gboolean ret = FALSE;
GstGLMixer *mix = GST_GL_MIXER (agg);
GST_TRACE ("QUERY %" GST_PTR_FORMAT, query);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CAPS:
{
GstCaps *filter, *caps;
gst_query_parse_caps (query, &filter);
caps = gst_gl_mixer_pad_sink_getcaps (GST_PAD (bpad), mix, filter);
gst_query_set_caps_result (query, caps);
gst_caps_unref (caps);
ret = TRUE;
break;
}
case GST_QUERY_ACCEPT_CAPS:
{
GstCaps *caps;
gst_query_parse_accept_caps (query, &caps);
ret = gst_gl_mixer_pad_sink_acceptcaps (GST_PAD (bpad), mix, caps);
gst_query_set_accept_caps_result (query, ret);
ret = TRUE;
break;
}
default:
ret = GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query);
break;
}
return ret;
}
static void
gst_gl_mixer_pad_init (GstGLMixerPad * mixerpad)
{
}
/* GLMixer signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
PROP_0,
};
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
"RGBA"))
);
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
GST_PAD_SINK,
GST_PAD_REQUEST,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
"RGBA"))
);
static gboolean gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query);
static gboolean gst_gl_mixer_stop (GstAggregator * agg);
static gboolean gst_gl_mixer_start (GstAggregator * agg);
static GstFlowReturn
gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg,
GstBuffer * outbuffer);
static void gst_gl_mixer_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_mixer_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_gl_mixer_decide_allocation (GstAggregator * agg,
GstQuery * query);
static void gst_gl_mixer_finalize (GObject * object);
static void
gst_gl_mixer_class_init (GstGLMixerClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoAggregatorClass *videoaggregator_class =
(GstVideoAggregatorClass *) klass;
GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "OpenGL mixer");
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gl_mixer_finalize);
gobject_class->get_property = gst_gl_mixer_get_property;
gobject_class->set_property = gst_gl_mixer_set_property;
gst_element_class_add_static_pad_template_with_gtype (element_class,
&src_factory, GST_TYPE_AGGREGATOR_PAD);
gst_element_class_add_static_pad_template_with_gtype (element_class,
&sink_factory, GST_TYPE_GL_MIXER_PAD);
agg_class->sink_query = gst_gl_mixer_sink_query;
agg_class->src_query = gst_gl_mixer_src_query;
agg_class->stop = gst_gl_mixer_stop;
agg_class->start = gst_gl_mixer_start;
agg_class->negotiated_src_caps = _negotiated_caps;
agg_class->decide_allocation = gst_gl_mixer_decide_allocation;
agg_class->propose_allocation = gst_gl_mixer_propose_allocation;
videoaggregator_class->aggregate_frames = gst_gl_mixer_aggregate_frames;
videoaggregator_class->find_best_format = _find_best_format;
/* Register the pad class */
g_type_class_ref (GST_TYPE_GL_MIXER_PAD);
klass->set_caps = NULL;
}
static void
gst_gl_mixer_reset (GstGLMixer * mix)
{
mix->priv->negotiated = FALSE;
}
static void
gst_gl_mixer_init (GstGLMixer * mix)
{
mix->priv = gst_gl_mixer_get_instance_private (mix);
mix->priv->gl_resource_ready = FALSE;
g_mutex_init (&mix->priv->gl_resource_lock);
g_cond_init (&mix->priv->gl_resource_cond);
/* initialize variables */
gst_gl_mixer_reset (mix);
}
static void
gst_gl_mixer_finalize (GObject * object)
{
GstGLMixer *mix = GST_GL_MIXER (object);
GstGLMixerPrivate *priv = mix->priv;
if (mix->out_caps)
gst_caps_unref (mix->out_caps);
g_mutex_clear (&priv->gl_resource_lock);
g_cond_clear (&priv->gl_resource_cond);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
gst_gl_mixer_query_caps (GstPad * pad, GstAggregator * agg, GstQuery * query)
{
GstCaps *filter, *current_caps, *retcaps, *template_caps;
gst_query_parse_caps (query, &filter);
template_caps = gst_pad_get_pad_template_caps (agg->srcpad);
current_caps = gst_pad_get_current_caps (pad);
if (current_caps == NULL)
retcaps = gst_caps_ref (template_caps);
else {
retcaps = gst_caps_merge (current_caps, template_caps);
template_caps = NULL;
}
if (filter) {
current_caps =
gst_caps_intersect_full (filter, retcaps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (retcaps);
retcaps = current_caps;
}
gst_query_set_caps_result (query, retcaps);
gst_caps_unref (retcaps);
if (template_caps)
gst_caps_unref (template_caps);
return TRUE;
}
static gboolean
gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query)
{
gboolean res = FALSE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CAPS:
res = gst_gl_mixer_query_caps (agg->srcpad, agg, query);
break;
default:
res = GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
break;
}
return res;
}
static void
_mixer_create_fbo (GstGLContext * context, GstGLMixer * mix)
{
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
guint out_width = GST_VIDEO_INFO_WIDTH (&vagg->info);
guint out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info);
mix->fbo =
gst_gl_framebuffer_new_with_default_depth (context, out_width,
out_height);
}
static gboolean
gst_gl_mixer_decide_allocation (GstAggregator * agg, GstQuery * query)
{
GstGLBaseMixer *base_mix = GST_GL_BASE_MIXER (agg);
GstGLMixer *mix = GST_GL_MIXER (base_mix);
GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
GstGLContext *context;
GstBufferPool *pool = NULL;
GstStructure *config;
GstCaps *caps;
guint min, max, size;
gboolean update_pool;
if (!GST_AGGREGATOR_CLASS (gst_gl_mixer_parent_class)->decide_allocation (agg,
query))
return FALSE;
context = base_mix->context;
g_mutex_lock (&mix->priv->gl_resource_lock);
mix->priv->gl_resource_ready = FALSE;
if (mix->fbo)
gst_object_unref (mix->fbo);
gst_gl_context_thread_add (context,
(GstGLContextThreadFunc) _mixer_create_fbo, mix);
if (!mix->fbo) {
g_cond_signal (&mix->priv->gl_resource_cond);
g_mutex_unlock (&mix->priv->gl_resource_lock);
goto context_error;
}
gst_query_parse_allocation (query, &caps, NULL);
if (mixer_class->set_caps)
mixer_class->set_caps (mix, caps);
mix->priv->gl_resource_ready = TRUE;
g_cond_signal (&mix->priv->gl_resource_cond);
g_mutex_unlock (&mix->priv->gl_resource_lock);
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)
pool = gst_gl_buffer_pool_new (context);
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, caps, size, min, max);
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
gst_buffer_pool_set_config (pool, config);
if (update_pool)
gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
else
gst_query_add_allocation_pool (query, pool, size, min, max);
gst_object_unref (pool);
return TRUE;
context_error:
{
GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("Context error"), (NULL));
return FALSE;
}
}
gboolean
gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf)
{
GstGLMemory *out_tex;
gboolean res = TRUE;
GstVideoFrame out_frame;
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
GstGLMixerPrivate *priv = mix->priv;
GST_TRACE ("Processing buffers");
if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf,
GST_MAP_WRITE | GST_MAP_GL)) {
return FALSE;
}
out_tex = (GstGLMemory *) out_frame.map[0].memory;
g_mutex_lock (&priv->gl_resource_lock);
if (!priv->gl_resource_ready)
g_cond_wait (&priv->gl_resource_cond, &priv->gl_resource_lock);
if (!priv->gl_resource_ready) {
g_mutex_unlock (&priv->gl_resource_lock);
GST_ERROR_OBJECT (mix,
"fbo used to render can't be created, do not run process_textures");
res = FALSE;
goto out;
}
mix_class->process_textures (mix, out_tex);
g_mutex_unlock (&priv->gl_resource_lock);
out:
gst_video_frame_unmap (&out_frame);
return res;
}
static gboolean
gst_gl_mixer_process_buffers (GstGLMixer * mix, GstBuffer * outbuf)
{
GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
return mix_class->process_buffers (mix, outbuf);
}
static GstFlowReturn
gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
{
gboolean res = FALSE;
GstGLMixer *mix = GST_GL_MIXER (vagg);
GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (vagg);
GstGLContext *context = GST_GL_BASE_MIXER (mix)->context;
GstGLSyncMeta *sync_meta;
if (mix_class->process_buffers)
res = gst_gl_mixer_process_buffers (mix, outbuf);
else if (mix_class->process_textures)
res = gst_gl_mixer_process_textures (mix, outbuf);
sync_meta = gst_buffer_get_gl_sync_meta (outbuf);
if (sync_meta)
gst_gl_sync_meta_set_sync_point (sync_meta, context);
return res ? GST_FLOW_OK : GST_FLOW_ERROR;
}
static void
gst_gl_mixer_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_mixer_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_mixer_start (GstAggregator * agg)
{
return GST_AGGREGATOR_CLASS (parent_class)->start (agg);
}
static gboolean
gst_gl_mixer_stop (GstAggregator * agg)
{
GstGLMixer *mix = GST_GL_MIXER (agg);
GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
if (mixer_class->reset)
mixer_class->reset (mix);
if (mix->fbo) {
gst_object_unref (mix->fbo);
mix->fbo = NULL;
}
gst_gl_mixer_reset (mix);
return GST_AGGREGATOR_CLASS (parent_class)->stop (agg);
}

View file

@ -1,110 +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_MIXER_H__
#define __GST_GL_MIXER_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
#include <gst/gl/gstglfuncs.h>
#include "gstglbasemixer.h"
G_BEGIN_DECLS
typedef struct _GstGLMixer GstGLMixer;
typedef struct _GstGLMixerClass GstGLMixerClass;
typedef struct _GstGLMixerPrivate GstGLMixerPrivate;
#define GST_TYPE_GL_MIXER_PAD (gst_gl_mixer_pad_get_type())
#define GST_GL_MIXER_PAD(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_MIXER_PAD, GstGLMixerPad))
#define GST_GL_MIXER_PAD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_MIXER_PAD, GstGLMixerPadClass))
#define GST_IS_GL_MIXER_PAD(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_MIXER_PAD))
#define GST_IS_GL_MIXER_PAD_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_MIXER_PAD))
#define GST_GL_MIXER_PAD_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_GL_MIXER_PAD,GstGLMixerPadClass))
typedef struct _GstGLMixerPad GstGLMixerPad;
typedef struct _GstGLMixerPadClass GstGLMixerPadClass;
/* all information needed for one video stream */
struct _GstGLMixerPad
{
GstGLBaseMixerPad parent;
guint current_texture;
};
struct _GstGLMixerPadClass
{
GstGLBaseMixerPadClass parent_class;
};
GType gst_gl_mixer_pad_get_type (void);
#define GST_TYPE_GL_MIXER (gst_gl_mixer_get_type())
#define GST_GL_MIXER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_MIXER, GstGLMixer))
#define GST_GL_MIXER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_MIXER, GstGLMixerClass))
#define GST_IS_GL_MIXER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_MIXER))
#define GST_IS_GL_MIXER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_MIXER))
#define GST_GL_MIXER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_GL_MIXER,GstGLMixerClass))
typedef gboolean (*GstGLMixerSetCaps) (GstGLMixer* mixer,
GstCaps* outcaps);
typedef void (*GstGLMixerReset) (GstGLMixer *mixer);
typedef gboolean (*GstGLMixerProcessFunc) (GstGLMixer *mix, GstBuffer *outbuf);
typedef gboolean (*GstGLMixerProcessTextures) (GstGLMixer *mix, GstGLMemory *out_tex);
struct _GstGLMixer
{
GstGLBaseMixer vaggregator;
GstGLFramebuffer *fbo;
GstCaps *out_caps;
GstGLMixerPrivate *priv;
};
struct _GstGLMixerClass
{
GstGLBaseMixerClass parent_class;
GstGLMixerSetCaps set_caps;
GstGLMixerReset reset;
GstGLMixerProcessFunc process_buffers;
GstGLMixerProcessTextures process_textures;
};
GType gst_gl_mixer_get_type(void);
gboolean gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf);
G_END_DECLS
#endif /* __GST_GL_MIXER_H__ */

View file

@ -1,629 +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/gst.h>
#include "gstglmixerbin.h"
#define GST_CAT_DEFAULT gst_gl_mixer_bin_debug
GST_DEBUG_CATEGORY (gst_gl_mixer_bin_debug);
#define DEFAULT_LATENCY 0
#define DEFAULT_START_TIME_SELECTION 0
#define DEFAULT_START_TIME (-1)
typedef enum
{
GST_GL_MIXER_BIN_START_TIME_SELECTION_ZERO,
GST_GL_MIXER_BIN_START_TIME_SELECTION_FIRST,
GST_GL_MIXER_BIN_START_TIME_SELECTION_SET
} GstGLMixerBinStartTimeSelection;
static GType
gst_gl_mixer_bin_start_time_selection_get_type (void)
{
static GType gtype = 0;
if (gtype == 0) {
static const GEnumValue values[] = {
{GST_GL_MIXER_BIN_START_TIME_SELECTION_ZERO,
"Start at 0 running time (default)", "zero"},
{GST_GL_MIXER_BIN_START_TIME_SELECTION_FIRST,
"Start at first observed input running time", "first"},
{GST_GL_MIXER_BIN_START_TIME_SELECTION_SET,
"Set start time with start-time property", "set"},
{0, NULL, NULL}
};
gtype = g_enum_register_static ("GstGLMixerBinStartTimeSelection", values);
}
return gtype;
}
struct input_chain
{
GstGLMixerBin *self;
GstGhostPad *ghost_pad;
GstElement *upload;
GstElement *in_convert;
GstElement *in_overlay;
GstPad *mixer_pad;
};
static void
_free_input_chain (struct input_chain *chain)
{
if (!chain)
return;
chain->ghost_pad = NULL;
if (chain->upload) {
gst_element_set_state (chain->upload, GST_STATE_NULL);
gst_bin_remove (GST_BIN (chain->self), chain->upload);
chain->upload = NULL;
}
if (chain->in_convert) {
gst_element_set_state (chain->in_convert, GST_STATE_NULL);
gst_bin_remove (GST_BIN (chain->self), chain->in_convert);
chain->in_convert = NULL;
}
if (chain->in_overlay) {
gst_element_set_state (chain->in_overlay, GST_STATE_NULL);
gst_bin_remove (GST_BIN (chain->self), chain->in_overlay);
chain->in_overlay = NULL;
}
if (chain->mixer_pad) {
gst_element_release_request_pad (chain->self->mixer, chain->mixer_pad);
gst_object_unref (chain->mixer_pad);
chain->mixer_pad = NULL;
}
g_free (chain);
}
struct _GstGLMixerBinPrivate
{
gboolean running;
GList *input_chains;
};
enum
{
PROP_0,
PROP_MIXER,
PROP_LATENCY,
PROP_START_TIME_SELECTION,
PROP_START_TIME,
};
enum
{
SIGNAL_0,
SIGNAL_CREATE_ELEMENT,
LAST_SIGNAL
};
static void gst_gl_mixer_bin_child_proxy_init (gpointer g_iface,
gpointer iface_data);
G_DEFINE_TYPE_WITH_CODE (GstGLMixerBin, gst_gl_mixer_bin, GST_TYPE_BIN,
G_ADD_PRIVATE (GstGLMixerBin)
G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
gst_gl_mixer_bin_child_proxy_init));
static guint gst_gl_mixer_bin_signals[LAST_SIGNAL] = { 0 };
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw(ANY)")
);
static void gst_gl_mixer_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_mixer_bin_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_mixer_bin_dispose (GObject * object);
static GstPad *gst_gl_mixer_bin_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps);
static void gst_gl_mixer_bin_release_pad (GstElement * element, GstPad * pad);
static GstStateChangeReturn gst_gl_mixer_bin_change_state (GstElement *
element, GstStateChange transition);
static void
gst_gl_mixer_bin_class_init (GstGLMixerBinClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstCaps *upload_caps;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixerbin", 0,
"opengl mixer bin");
element_class->request_new_pad = gst_gl_mixer_bin_request_new_pad;
element_class->release_pad = gst_gl_mixer_bin_release_pad;
element_class->change_state = gst_gl_mixer_bin_change_state;
gobject_class->get_property = gst_gl_mixer_bin_get_property;
gobject_class->set_property = gst_gl_mixer_bin_set_property;
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_gl_mixer_bin_dispose);
g_object_class_install_property (gobject_class, PROP_MIXER,
g_param_spec_object ("mixer",
"GL mixer element",
"The GL mixer chain to use",
GST_TYPE_ELEMENT,
GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_LATENCY,
g_param_spec_uint64 ("latency", "Buffer latency",
"Additional latency in live mode to allow upstream "
"to take longer to produce buffers for the current "
"position (in nanoseconds)", 0, G_MAXUINT64,
DEFAULT_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_START_TIME_SELECTION,
g_param_spec_enum ("start-time-selection", "Start Time Selection",
"Decides which start time is output",
gst_gl_mixer_bin_start_time_selection_get_type (),
DEFAULT_START_TIME_SELECTION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_START_TIME,
g_param_spec_uint64 ("start-time", "Start Time",
"Start time to use if start-time-selection=set", 0,
G_MAXUINT64,
DEFAULT_START_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstMixerBin::create-element:
* @object: the #GstGLMixerBin
*
* Will be emitted when we need the processing element/s that this bin will use
*
* Returns: a new #GstElement
*/
gst_gl_mixer_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_add_static_pad_template (element_class, &src_factory);
upload_caps = gst_gl_upload_get_input_template_caps ();
gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
upload_caps));
gst_caps_unref (upload_caps);
gst_element_class_set_metadata (element_class, "OpenGL video_mixer empty bin",
"Bin/Filter/Effect/Video/Mixer", "OpenGL video_mixer empty bin",
"Matthew Waters <matthew@centricular.com>");
}
static void
gst_gl_mixer_bin_init (GstGLMixerBin * self)
{
gboolean res = TRUE;
GstPad *pad;
self->priv = gst_gl_mixer_bin_get_instance_private (self);
self->out_convert = gst_element_factory_make ("glcolorconvert", NULL);
self->download = gst_element_factory_make ("gldownload", NULL);
res &= gst_bin_add (GST_BIN (self), self->out_convert);
res &= gst_bin_add (GST_BIN (self), self->download);
res &=
gst_element_link_pads (self->out_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_ERROR_OBJECT (self, "failed to create output chain");
}
static void
gst_gl_mixer_bin_dispose (GObject * object)
{
GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
GList *l = self->priv->input_chains;
while (l) {
struct input_chain *chain = l->data;
if (self->mixer && chain->mixer_pad) {
gst_element_release_request_pad (GST_ELEMENT (self->mixer),
chain->mixer_pad);
gst_object_unref (chain->mixer_pad);
chain->mixer_pad = NULL;
}
l = l->next;
}
g_list_free_full (self->priv->input_chains, (GDestroyNotify) g_free);
G_OBJECT_CLASS (gst_gl_mixer_bin_parent_class)->dispose (object);
}
static gboolean
_create_input_chain (GstGLMixerBin * self, struct input_chain *chain,
GstPad * mixer_pad)
{
GstGLMixerBinClass *klass = GST_GL_MIXER_BIN_GET_CLASS (self);
GstPad *pad;
gboolean res = TRUE;
gchar *name;
chain->self = self;
chain->mixer_pad = mixer_pad;
chain->upload = gst_element_factory_make ("glupload", NULL);
chain->in_convert = gst_element_factory_make ("glcolorconvert", NULL);
chain->in_overlay = gst_element_factory_make ("gloverlaycompositor", NULL);
res &= gst_bin_add (GST_BIN (self), chain->in_convert);
res &= gst_bin_add (GST_BIN (self), chain->in_overlay);
res &= gst_bin_add (GST_BIN (self), chain->upload);
pad = gst_element_get_static_pad (chain->in_overlay, "src");
if (gst_pad_link (pad, mixer_pad) != GST_PAD_LINK_OK) {
gst_object_unref (pad);
return FALSE;
}
gst_object_unref (pad);
res &=
gst_element_link_pads (chain->in_convert, "src", chain->in_overlay,
"sink");
res &=
gst_element_link_pads (chain->upload, "src", chain->in_convert, "sink");
pad = gst_element_get_static_pad (chain->upload, "sink");
if (!pad) {
return FALSE;
} else {
GST_DEBUG_OBJECT (self, "setting target sink pad %" GST_PTR_FORMAT, pad);
name = gst_object_get_name (GST_OBJECT (mixer_pad));
if (klass->create_input_pad) {
chain->ghost_pad = klass->create_input_pad (self, chain->mixer_pad);
gst_object_set_name (GST_OBJECT (chain->ghost_pad), name);
gst_ghost_pad_set_target (chain->ghost_pad, pad);
} else {
chain->ghost_pad =
GST_GHOST_PAD (gst_ghost_pad_new (GST_PAD_NAME (chain->mixer_pad),
pad));
}
g_free (name);
GST_OBJECT_LOCK (self);
if (self->priv->running)
gst_pad_set_active (GST_PAD (chain->ghost_pad), TRUE);
GST_OBJECT_UNLOCK (self);
gst_element_add_pad (GST_ELEMENT_CAST (self), GST_PAD (chain->ghost_pad));
gst_object_unref (pad);
}
gst_element_sync_state_with_parent (chain->upload);
gst_element_sync_state_with_parent (chain->in_convert);
gst_element_sync_state_with_parent (chain->in_overlay);
return TRUE;
}
static GstPadTemplate *
_find_element_pad_template (GstElement * element,
GstPadDirection direction, GstPadPresence presence)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
GList *templ_list = gst_element_class_get_pad_template_list (klass);
GstPadTemplate *templ;
/* find suitable template */
while (templ_list) {
templ = (GstPadTemplate *) templ_list->data;
if (GST_PAD_TEMPLATE_DIRECTION (templ) != direction
|| GST_PAD_TEMPLATE_PRESENCE (templ) != presence) {
templ_list = templ_list->next;
templ = NULL;
continue;
}
break;
}
return templ;
}
static gboolean
_connect_mixer_element (GstGLMixerBin * self)
{
gboolean res = TRUE;
g_return_val_if_fail (self->priv->input_chains == NULL, FALSE);
gst_object_set_name (GST_OBJECT (self->mixer), "mixer");
res &= gst_bin_add (GST_BIN (self), self->mixer);
res &= gst_element_link_pads (self->mixer, "src", self->out_convert, "sink");
if (!res)
GST_ERROR_OBJECT (self, "Failed to link mixer element into the pipeline");
gst_element_sync_state_with_parent (self->mixer);
return res;
}
void
gst_gl_mixer_bin_finish_init_with_element (GstGLMixerBin * self,
GstElement * element)
{
g_return_if_fail (GST_IS_ELEMENT (element));
self->mixer = element;
if (!_connect_mixer_element (self)) {
gst_object_unref (self->mixer);
self->mixer = NULL;
}
}
void
gst_gl_mixer_bin_finish_init (GstGLMixerBin * self)
{
GstGLMixerBinClass *klass = GST_GL_MIXER_BIN_GET_CLASS (self);
GstElement *element = NULL;
if (klass->create_element)
element = klass->create_element ();
if (element)
gst_gl_mixer_bin_finish_init_with_element (self, element);
}
static void
gst_gl_mixer_bin_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
switch (prop_id) {
case PROP_MIXER:
g_value_set_object (value, self->mixer);
break;
default:
if (self->mixer)
g_object_get_property (G_OBJECT (self->mixer), pspec->name, value);
break;
}
}
static void
gst_gl_mixer_bin_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
switch (prop_id) {
case PROP_MIXER:
{
GstElement *mixer = g_value_get_object (value);
/* FIXME: deal with replacing a mixer */
g_return_if_fail (!self->mixer || (self->mixer == mixer));
self->mixer = mixer;
if (mixer) {
gst_object_ref_sink (mixer);
_connect_mixer_element (self);
}
break;
}
default:
if (self->mixer)
g_object_set_property (G_OBJECT (self->mixer), pspec->name, value);
break;
}
}
static GstPad *
gst_gl_mixer_bin_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * req_name, const GstCaps * caps)
{
GstGLMixerBin *self = GST_GL_MIXER_BIN (element);
GstPadTemplate *mixer_templ;
struct input_chain *chain;
GstPad *mixer_pad;
chain = g_new0 (struct input_chain, 1);
mixer_templ = _find_element_pad_template (self->mixer,
GST_PAD_TEMPLATE_DIRECTION (templ), GST_PAD_TEMPLATE_PRESENCE (templ));
g_return_val_if_fail (mixer_templ, NULL);
mixer_pad =
gst_element_request_pad (self->mixer, mixer_templ, req_name, NULL);
g_return_val_if_fail (mixer_pad, NULL);
if (!_create_input_chain (self, chain, mixer_pad)) {
gst_element_release_request_pad (self->mixer, mixer_pad);
_free_input_chain (chain);
return NULL;
}
GST_OBJECT_LOCK (element);
self->priv->input_chains = g_list_prepend (self->priv->input_chains, chain);
GST_OBJECT_UNLOCK (element);
gst_child_proxy_child_added (GST_CHILD_PROXY (self),
G_OBJECT (chain->ghost_pad), GST_OBJECT_NAME (chain->ghost_pad));
return GST_PAD (chain->ghost_pad);
}
static void
gst_gl_mixer_bin_release_pad (GstElement * element, GstPad * pad)
{
GstGLMixerBin *self = GST_GL_MIXER_BIN (element);
GList *l = self->priv->input_chains;
gboolean released = FALSE;
GST_OBJECT_LOCK (element);
while (l) {
struct input_chain *chain = l->data;
if (GST_PAD (chain->ghost_pad) == pad) {
self->priv->input_chains =
g_list_delete_link (self->priv->input_chains, l);
GST_OBJECT_UNLOCK (element);
_free_input_chain (chain);
gst_element_remove_pad (element, pad);
released = TRUE;
break;
}
l = l->next;
}
if (!released)
GST_OBJECT_UNLOCK (element);
}
static GstStateChangeReturn
gst_gl_mixer_bin_change_state (GstElement * element, GstStateChange transition)
{
GstGLMixerBin *self = GST_GL_MIXER_BIN (element);
GstGLMixerBinClass *klass = GST_GL_MIXER_BIN_GET_CLASS (self);
GstStateChangeReturn ret;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
GST_OBJECT_LOCK (element);
if (!self->mixer) {
if (klass->create_element)
self->mixer = klass->create_element ();
if (!self->mixer)
g_signal_emit (element,
gst_gl_mixer_bin_signals[SIGNAL_CREATE_ELEMENT], 0, &self->mixer);
if (!self->mixer) {
GST_ERROR_OBJECT (element, "Failed to retrieve element");
GST_OBJECT_UNLOCK (element);
return GST_STATE_CHANGE_FAILURE;
}
GST_OBJECT_UNLOCK (element);
if (!_connect_mixer_element (self))
return GST_STATE_CHANGE_FAILURE;
GST_OBJECT_LOCK (element);
}
self->priv->running = TRUE;
GST_OBJECT_UNLOCK (element);
break;
default:
break;
}
ret =
GST_ELEMENT_CLASS (gst_gl_mixer_bin_parent_class)->change_state (element,
transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
switch (transition) {
case GST_STATE_CHANGE_READY_TO_NULL:
GST_OBJECT_LOCK (self);
self->priv->running = FALSE;
GST_OBJECT_UNLOCK (self);
default:
break;
}
return ret;
}
static GObject *
gst_gl_mixer_bin_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
guint index)
{
GstGLMixerBin *mixer = GST_GL_MIXER_BIN (child_proxy);
GstBin *bin = GST_BIN_CAST (child_proxy);
GObject *res = NULL;
GST_OBJECT_LOCK (bin);
/* XXX: not exactly thread safe with ordering */
if (index < bin->numchildren) {
if ((res = g_list_nth_data (bin->children, index)))
gst_object_ref (res);
} else {
struct input_chain *chain;
if ((chain =
g_list_nth_data (mixer->priv->input_chains,
index - bin->numchildren))) {
res = gst_object_ref (chain->ghost_pad);
}
}
GST_OBJECT_UNLOCK (bin);
return res;
}
static guint
gst_gl_mixer_bin_child_proxy_get_children_count (GstChildProxy * child_proxy)
{
GstGLMixerBin *mixer = GST_GL_MIXER_BIN (child_proxy);
GstBin *bin = GST_BIN_CAST (child_proxy);
guint num;
GST_OBJECT_LOCK (bin);
num = bin->numchildren + g_list_length (mixer->priv->input_chains);
GST_OBJECT_UNLOCK (bin);
return num;
}
static void
gst_gl_mixer_bin_child_proxy_init (gpointer g_iface, gpointer iface_data)
{
GstChildProxyInterface *iface = g_iface;
iface->get_children_count = gst_gl_mixer_bin_child_proxy_get_children_count;
iface->get_child_by_index = gst_gl_mixer_bin_child_proxy_get_child_by_index;
}

View file

@ -1,72 +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_MIXER_BIN_H__
#define __GST_GL_MIXER_BIN_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
GType gst_gl_mixer_bin_get_type(void);
#define GST_TYPE_GL_MIXER_BIN (gst_gl_mixer_bin_get_type())
#define GST_GL_MIXER_BIN(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_MIXER_BIN, GstGLMixerBin))
#define GST_GL_MIXER_BIN_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_MIXER_BIN, GstGLMixerBinClass))
#define GST_IS_GL_MIXER_BIN(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_MIXER_BIN))
#define GST_IS_GL_MIXER_BIN_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_MIXER_BIN))
#define GST_GL_MIXER_BIN_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_GL_MIXER_BIN,GstGLMixerBinClass))
typedef struct _GstGLMixerBin GstGLMixerBin;
typedef struct _GstGLMixerBinClass GstGLMixerBinClass;
typedef struct _GstGLMixerBinPrivate GstGLMixerBinPrivate;
struct _GstGLMixerBin
{
GstBin parent;
GstElement *mixer;
GstElement *out_convert;
GstElement *download;
GstPad *srcpad;
GstGLMixerBinPrivate *priv;
};
struct _GstGLMixerBinClass
{
GstBinClass parent_class;
GstElement * (*create_element) (void);
GstGhostPad * (*create_input_pad) (GstGLMixerBin * self, GstPad * mixer_pad);
};
void gst_gl_mixer_bin_finish_init (GstGLMixerBin * self);
void gst_gl_mixer_bin_finish_init_with_element (GstGLMixerBin * self,
GstElement * element);
G_END_DECLS
#endif /* __GST_GL_MIXER_BIN_H__ */

View file

@ -1,449 +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.
*/
/**
* SECTION:element-glmosaic
* @title: glmosaic
*
* glmixer sub element. N gl sink pads to 1 source pad.
* N + 1 OpenGL contexts shared together.
* N <= 6 because the rendering is more a like a cube than a mosaic
* Each opengl input stream is rendered on a cube face
*
* ## Examples
* |[
* gst-launch-1.0 videotestsrc ! video/x-raw, format=YUY2 ! queue ! glmosaic name=m ! glimagesink \
* videotestsrc pattern=12 ! video/x-raw, format=I420, framerate=5/1, width=100, height=200 ! queue ! m. \
* videotestsrc ! video/x-raw, framerate=15/1, width=1500, height=1500 ! gleffects effect=3 ! queue ! m. \
* videotestsrc ! gleffects effect=2 ! queue ! m. \
* videotestsrc ! glfiltercube ! queue ! m. \
* videotestsrc ! gleffects effect=6 ! queue ! m.
* ]|
* FBO (Frame Buffer Object) is required.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglmosaic.h"
#include "gstglutils.h"
#define GST_CAT_DEFAULT gst_gl_mosaic_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0,
};
static void gst_gl_mosaic_child_proxy_init (gpointer g_iface,
gpointer iface_data);
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_mosaic_debug, "glmosaic", 0, "glmosaic element");
G_DEFINE_TYPE_WITH_CODE (GstGLMosaic, gst_gl_mosaic, GST_TYPE_GL_MIXER,
G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
gst_gl_mosaic_child_proxy_init);
DEBUG_INIT);
static void gst_gl_mosaic_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_mosaic_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstPad *gst_gl_mosaic_request_new_pad (GstElement * element,
GstPadTemplate * temp, const gchar * req_name, const GstCaps * caps);
static void gst_gl_mosaic_release_pad (GstElement * element, GstPad * pad);
static void gst_gl_mosaic_reset (GstGLMixer * mixer);
static gboolean gst_gl_mosaic_init_shader (GstGLMixer * mixer,
GstCaps * outcaps);
static gboolean gst_gl_mosaic_process_textures (GstGLMixer * mixer,
GstGLMemory * out_tex);
static gboolean gst_gl_mosaic_callback (gpointer stuff);
//vertex source
static const gchar *mosaic_v_src =
"uniform mat4 u_matrix; \n"
"uniform float xrot_degree, yrot_degree, zrot_degree; \n"
"attribute vec4 a_position; \n"
"attribute vec2 a_texCoord; \n"
"varying vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" float PI = 3.14159265; \n"
" float xrot = xrot_degree*2.0*PI/360.0; \n"
" float yrot = yrot_degree*2.0*PI/360.0; \n"
" float zrot = zrot_degree*2.0*PI/360.0; \n"
" mat4 matX = mat4 ( \n"
" 1.0, 0.0, 0.0, 0.0, \n"
" 0.0, cos(xrot), sin(xrot), 0.0, \n"
" 0.0, -sin(xrot), cos(xrot), 0.0, \n"
" 0.0, 0.0, 0.0, 1.0 ); \n"
" mat4 matY = mat4 ( \n"
" cos(yrot), 0.0, -sin(yrot), 0.0, \n"
" 0.0, 1.0, 0.0, 0.0, \n"
" sin(yrot), 0.0, cos(yrot), 0.0, \n"
" 0.0, 0.0, 0.0, 1.0 ); \n"
" mat4 matZ = mat4 ( \n"
" cos(zrot), sin(zrot), 0.0, 0.0, \n"
" -sin(zrot), cos(zrot), 0.0, 0.0, \n"
" 0.0, 0.0, 1.0, 0.0, \n"
" 0.0, 0.0, 0.0, 1.0 ); \n"
" gl_Position = u_matrix * matZ * matY * matX * a_position; \n"
" v_texCoord = a_texCoord; \n"
"} \n";
//fragment source
static const gchar *mosaic_f_src =
"uniform sampler2D s_texture; \n"
"varying vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
//" gl_FragColor = vec4( 1.0, 0.5, 1.0, 1.0 );\n"
" gl_FragColor = texture2D( s_texture, v_texCoord );\n"
"} \n";
static void
gst_gl_mosaic_class_init (GstGLMosaicClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_mosaic_set_property;
gobject_class->get_property = gst_gl_mosaic_get_property;
element_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_gl_mosaic_request_new_pad);
element_class->release_pad = GST_DEBUG_FUNCPTR (gst_gl_mosaic_release_pad);
gst_element_class_set_metadata (element_class, "OpenGL mosaic",
"Filter/Effect/Video", "OpenGL mosaic",
"Julien Isorce <julien.isorce@gmail.com>");
GST_GL_MIXER_CLASS (klass)->set_caps = gst_gl_mosaic_init_shader;
GST_GL_MIXER_CLASS (klass)->reset = gst_gl_mosaic_reset;
GST_GL_MIXER_CLASS (klass)->process_textures = gst_gl_mosaic_process_textures;
GST_GL_BASE_MIXER_CLASS (klass)->supported_gl_api = GST_GL_API_OPENGL;
}
static void
gst_gl_mosaic_init (GstGLMosaic * mosaic)
{
mosaic->shader = NULL;
}
static void
gst_gl_mosaic_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
//GstGLMosaic *mixer = GST_GL_MOSAIC (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_mosaic_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
//GstGLMosaic* mixer = GST_GL_MOSAIC (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstPad *
gst_gl_mosaic_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * req_name, const GstCaps * caps)
{
GstPad *newpad;
newpad = (GstPad *)
GST_ELEMENT_CLASS (gst_gl_mosaic_parent_class)->request_new_pad (element,
templ, req_name, caps);
if (newpad == NULL)
goto could_not_create;
gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (newpad),
GST_OBJECT_NAME (newpad));
return newpad;
could_not_create:
{
GST_DEBUG_OBJECT (element, "could not create/add pad");
return NULL;
}
}
static void
gst_gl_mosaic_release_pad (GstElement * element, GstPad * pad)
{
GstGLMosaic *gl_mosaic = GST_GL_MOSAIC (element);
GST_DEBUG_OBJECT (gl_mosaic, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
gst_child_proxy_child_removed (GST_CHILD_PROXY (gl_mosaic), G_OBJECT (pad),
GST_OBJECT_NAME (pad));
GST_ELEMENT_CLASS (gst_gl_mosaic_parent_class)->release_pad (element, pad);
}
static void
gst_gl_mosaic_reset (GstGLMixer * mixer)
{
GstGLMosaic *mosaic = GST_GL_MOSAIC (mixer);
//blocking call, wait the opengl thread has destroyed the shader
if (mosaic->shader)
gst_object_unref (mosaic->shader);
mosaic->shader = NULL;
}
static gboolean
gst_gl_mosaic_init_shader (GstGLMixer * mixer, GstCaps * outcaps)
{
GstGLMosaic *mosaic = GST_GL_MOSAIC (mixer);
g_clear_object (&mosaic->shader);
//blocking call, wait the opengl thread has compiled the shader
return gst_gl_context_gen_shader (GST_GL_BASE_MIXER (mixer)->context,
mosaic_v_src, mosaic_f_src, &mosaic->shader);
}
static void
_mosaic_render (GstGLContext * context, GstGLMosaic * mosaic)
{
GstGLMixer *mixer = GST_GL_MIXER (mosaic);
gst_gl_framebuffer_draw_to_texture (mixer->fbo, mosaic->out_tex,
gst_gl_mosaic_callback, mosaic);
}
static gboolean
gst_gl_mosaic_process_textures (GstGLMixer * mix, GstGLMemory * out_tex)
{
GstGLMosaic *mosaic = GST_GL_MOSAIC (mix);
GstGLContext *context = GST_GL_BASE_MIXER (mix)->context;
mosaic->out_tex = out_tex;
gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _mosaic_render,
mosaic);
return TRUE;
}
/* opengl scene, params: input texture (not the output mixer->texture) */
static gboolean
gst_gl_mosaic_callback (gpointer stuff)
{
GstGLMosaic *mosaic = GST_GL_MOSAIC (stuff);
GstGLMixer *mixer = GST_GL_MIXER (mosaic);
GstGLFuncs *gl = GST_GL_BASE_MIXER (mixer)->context->gl_vtable;
GList *walk;
static GLfloat xrot = 0;
static GLfloat yrot = 0;
static GLfloat zrot = 0;
GLint attr_position_loc = 0;
GLint attr_texture_loc = 0;
const GLfloat matrix[] = {
0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
const GLushort indices[] = {
0, 1, 2,
0, 2, 3
};
guint count = 0;
gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context);
gl->BindTexture (GL_TEXTURE_2D, 0);
gl->Enable (GL_DEPTH_TEST);
gl->ClearColor (0.0, 0.0, 0.0, 0.0);
gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gst_gl_shader_use (mosaic->shader);
attr_position_loc =
gst_gl_shader_get_attribute_location (mosaic->shader, "a_position");
attr_texture_loc =
gst_gl_shader_get_attribute_location (mosaic->shader, "a_texCoord");
GST_OBJECT_LOCK (mosaic);
walk = GST_ELEMENT (mosaic)->sinkpads;
while (walk) {
GstGLMixerPad *pad = walk->data;
/* *INDENT-OFF* */
gfloat v_vertices[] = {
/* front face */
1.0f, 1.0f,-1.0f, 1.0f, 0.0f,
1.0f,-1.0f,-1.0f, 1.0f, 1.0f,
-1.0f,-1.0f,-1.0f, 0.0f, 1.0f,
-1.0f, 1.0f,-1.0f, 0.0f, 0.0f,
/* right face */
1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
1.0f,-1.0f, 1.0f, 0.0f, 0.0f,
1.0f,-1.0f,-1.0f, 0.0f, 1.0f,
1.0f, 1.0f,-1.0f, 1.0f, 1.0f,
/* left face */
-1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
-1.0f, 1.0f,-1.0f, 1.0f, 1.0f,
-1.0f,-1.0f,-1.0f, 0.0f, 1.0f,
-1.0f,-1.0f, 1.0f, 0.0f, 0.0f,
/* top face */
1.0f,-1.0f, 1.0f, 1.0f, 0.0f,
-1.0f,-1.0f, 1.0f, 0.0f, 0.0f,
-1.0f,-1.0f,-1.0f, 0.0f, 1.0f,
1.0f,-1.0f,-1.0f, 1.0f, 1.0f,
/* bottom face */
1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
1.0f, 1.0f,-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f,-1.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
/* back face */
1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
-1.0f,-1.0f, 1.0f, 0.0f, 1.0f,
1.0f,-1.0f, 1.0f, 1.0f, 1.0f
};
/* *INDENT-ON* */
guint in_tex;
guint width, height;
in_tex = pad->current_texture;
width = GST_VIDEO_INFO_WIDTH (&GST_VIDEO_AGGREGATOR_PAD (pad)->info);
height = GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR_PAD (pad)->info);
if (!in_tex || width <= 0 || height <= 0) {
GST_DEBUG ("skipping texture:%u pad:%p width:%u height %u",
in_tex, pad, width, height);
count++;
walk = g_list_next (walk);
continue;
}
GST_TRACE ("processing texture:%u dimensions:%ux%u", in_tex, width, height);
gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT,
GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[5 * 4 * count]);
gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT,
GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[5 * 4 * count + 3]);
gl->EnableVertexAttribArray (attr_position_loc);
gl->EnableVertexAttribArray (attr_texture_loc);
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, in_tex);
gst_gl_shader_set_uniform_1i (mosaic->shader, "s_texture", 0);
gst_gl_shader_set_uniform_1f (mosaic->shader, "xrot_degree", xrot);
gst_gl_shader_set_uniform_1f (mosaic->shader, "yrot_degree", yrot);
gst_gl_shader_set_uniform_1f (mosaic->shader, "zrot_degree", zrot);
gst_gl_shader_set_uniform_matrix_4fv (mosaic->shader, "u_matrix", 1,
GL_FALSE, matrix);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
++count;
walk = g_list_next (walk);
}
GST_OBJECT_UNLOCK (mosaic);
gl->DisableVertexAttribArray (attr_position_loc);
gl->DisableVertexAttribArray (attr_texture_loc);
gl->BindTexture (GL_TEXTURE_2D, 0);
gl->Disable (GL_DEPTH_TEST);
gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context);
xrot += 0.6f;
yrot += 0.4f;
zrot += 0.8f;
return TRUE;
}
/* GstChildProxy implementation */
static GObject *
gst_gl_mosaic_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
guint index)
{
GstGLMosaic *gl_mosaic = GST_GL_MOSAIC (child_proxy);
GObject *obj = NULL;
GST_OBJECT_LOCK (gl_mosaic);
obj = g_list_nth_data (GST_ELEMENT_CAST (gl_mosaic)->sinkpads, index);
if (obj)
gst_object_ref (obj);
GST_OBJECT_UNLOCK (gl_mosaic);
return obj;
}
static guint
gst_gl_mosaic_child_proxy_get_children_count (GstChildProxy * child_proxy)
{
guint count = 0;
GstGLMosaic *gl_mosaic = GST_GL_MOSAIC (child_proxy);
GST_OBJECT_LOCK (gl_mosaic);
count = GST_ELEMENT_CAST (gl_mosaic)->numsinkpads;
GST_OBJECT_UNLOCK (gl_mosaic);
GST_INFO_OBJECT (gl_mosaic, "Children Count: %d", count);
return count;
}
static void
gst_gl_mosaic_child_proxy_init (gpointer g_iface, gpointer iface_data)
{
GstChildProxyInterface *iface = g_iface;
iface->get_child_by_index = gst_gl_mosaic_child_proxy_get_child_by_index;
iface->get_children_count = gst_gl_mosaic_child_proxy_get_children_count;
}

View file

@ -1,55 +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_MOSAIC_H_
#define _GST_GL_MOSAIC_H_
#include "gstglmixer.h"
G_BEGIN_DECLS
#define GST_TYPE_GL_MOSAIC (gst_gl_mosaic_get_type())
#define GST_GL_MOSAIC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_MOSAIC,GstGLMosaic))
#define GST_IS_GL_MOSAIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_MOSAIC))
#define GST_GL_MOSAIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_MOSAIC,GstGLMosaicClass))
#define GST_IS_GL_MOSAIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_MOSAIC))
#define GST_GL_MOSAIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_MOSAIC,GstGLMosaicClass))
typedef struct _GstGLMosaic GstGLMosaic;
typedef struct _GstGLMosaicClass GstGLMosaicClass;
struct _GstGLMosaic
{
GstGLMixer mixer;
GstGLShader *shader;
GstGLMemory *out_tex;
};
struct _GstGLMosaicClass
{
GstGLMixerClass mixer_class;
};
GType gst_gl_mosaic_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERCUBE_H_ */

View file

@ -1,789 +0,0 @@
/*
* Combine video streams to 3D stereo
*
* GStreamer
* Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
* Copyright (C) 2014 Jan Schmidt <jan@noraisin.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* 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-glstereomix
* @title: glstereomix
*
* Combine 2 input streams to produce a stereoscopic output
* stream. Input views are taken from the left pad and right pad
* respectively, and mixed according to their timelines.
*
* If either input stream is stereoscopic, the approproriate view
* (left or right) is taken from each stream and placed into the output.
*
* The multiview representation on the output is chosen according to
* the downstream caps.
*
* ## Examples
* |[
* gst-launch-1.0 -v videotestsrc pattern=ball name=left \
* videotestsrc name=right glstereomix name=mix \
* left. ! vid/x-raw,width=640,height=480! glupload ! mix. \
* right. ! video/x-raw,width=640,height=480! glupload ! mix. \
* mix. ! video/x-raw'(memory:GLMemory)',multiview-mode=side-by-side ! \
* queue ! glimagesink output-multiview-mode=side-by-side
* ]| Mix 2 different videotestsrc patterns into a side-by-side stereo image and display it.
* |[
* gst-launch-1.0 -ev v4l2src name=left \
* videotestsrc name=right \
* glstereomix name=mix \
* left. ! video/x-raw,width=640,height=480 ! glupload ! glcolorconvert ! mix. \
* right. ! video/x-raw,width=640,height=480 ! glupload ! mix. \
* mix. ! video/x-raw'(memory:GLMemory)',multiview-mode=top-bottom ! \
* glcolorconvert ! gldownload ! queue ! x264enc ! h264parse ! \
* mp4mux ! progressreport ! filesink location=output.mp4
* ]| Mix the input from a camera to the left view, and videotestsrc to the right view,
* and encode as a top-bottom frame packed H.264 video.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglstereomix.h"
#define GST_CAT_DEFAULT gst_gl_stereo_mix_debug
GST_DEBUG_CATEGORY (gst_gl_stereo_mix_debug);
G_DEFINE_TYPE (GstGLStereoMixPad, gst_gl_stereo_mix_pad, GST_TYPE_GL_MIXER_PAD);
static void
gst_gl_stereo_mix_pad_class_init (GstGLStereoMixPadClass * klass)
{
}
static void
gst_gl_stereo_mix_pad_init (GstGLStereoMixPad * pad)
{
}
static void gst_gl_stereo_mix_child_proxy_init (gpointer g_iface,
gpointer iface_data);
#define gst_gl_stereo_mix_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstGLStereoMix, gst_gl_stereo_mix, GST_TYPE_GL_MIXER,
G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
gst_gl_stereo_mix_child_proxy_init));
static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps);
static gboolean _negotiated_caps (GstAggregator * aggregator, GstCaps * caps);
static gboolean gst_gl_stereo_mix_make_output (GstGLStereoMix * mix);
static gboolean gst_gl_stereo_mix_process_frames (GstGLStereoMix * mixer);
#define DEFAULT_DOWNMIX GST_GL_STEREO_DOWNMIX_ANAGLYPH_GREEN_MAGENTA_DUBOIS
/* GLStereoMix signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_DOWNMIX_MODE
};
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"
"; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
"RGBA")
"; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
);
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
GST_PAD_SINK,
GST_PAD_REQUEST,
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"
"; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
"RGBA")
"; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
);
static GstPad *gst_gl_stereo_mix_request_new_pad (GstElement * element,
GstPadTemplate * temp, const gchar * req_name, const GstCaps * caps);
static void gst_gl_stereo_mix_release_pad (GstElement * element, GstPad * pad);
static GstFlowReturn gst_gl_stereo_mix_create_output_buffer (GstVideoAggregator
* videoaggregator, GstBuffer ** outbuf);
static gboolean gst_gl_stereo_mix_stop (GstAggregator * agg);
static gboolean gst_gl_stereo_mix_start (GstAggregator * agg);
static gboolean gst_gl_stereo_mix_src_query (GstAggregator * agg,
GstQuery * query);
static void gst_gl_stereo_mix_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_stereo_mix_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_stereo_mix_finalize (GObject * object);
static GstFlowReturn
gst_gl_stereo_mix_aggregate_frames (GstVideoAggregator * vagg,
GstBuffer * outbuffer);
static void
gst_gl_stereo_mix_class_init (GstGLStereoMixClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoAggregatorClass *videoaggregator_class =
(GstVideoAggregatorClass *) klass;
GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
GstGLBaseMixerClass *base_mix_class = (GstGLBaseMixerClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glstereomixer", 0,
"opengl stereoscopic mixer");
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gl_stereo_mix_finalize);
gobject_class->get_property = gst_gl_stereo_mix_get_property;
gobject_class->set_property = gst_gl_stereo_mix_set_property;
gst_element_class_set_metadata (element_class, "OpenGL stereo video combiner",
"Filter/Effect/Video", "OpenGL stereo video combiner",
"Jan Schmidt <jan@centricular.com>");
g_object_class_install_property (gobject_class, PROP_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, DEFAULT_DOWNMIX,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_add_static_pad_template_with_gtype (element_class,
&src_factory, GST_TYPE_AGGREGATOR_PAD);
gst_element_class_add_static_pad_template_with_gtype (element_class,
&sink_factory, GST_TYPE_GL_STEREO_MIX_PAD);
element_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_gl_stereo_mix_request_new_pad);
element_class->release_pad =
GST_DEBUG_FUNCPTR (gst_gl_stereo_mix_release_pad);
agg_class->stop = gst_gl_stereo_mix_stop;
agg_class->start = gst_gl_stereo_mix_start;
agg_class->src_query = gst_gl_stereo_mix_src_query;
agg_class->negotiated_src_caps = _negotiated_caps;
videoaggregator_class->aggregate_frames = gst_gl_stereo_mix_aggregate_frames;
videoaggregator_class->update_caps = _update_caps;
videoaggregator_class->create_output_buffer =
gst_gl_stereo_mix_create_output_buffer;
base_mix_class->supported_gl_api =
GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
}
static void
gst_gl_stereo_mix_init (GstGLStereoMix * mix)
{
}
static void
gst_gl_stereo_mix_finalize (GObject * object)
{
//GstGLStereoMix *mix = GST_GL_STEREO_MIX (object);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
gst_gl_stereo_mix_query_caps (GstPad * pad, GstAggregator * agg,
GstQuery * query)
{
GstCaps *filter, *caps;
gst_query_parse_caps (query, &filter);
caps = gst_pad_get_current_caps (agg->srcpad);
if (caps == NULL) {
caps = gst_pad_get_pad_template_caps (agg->srcpad);
}
if (filter)
caps = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
gst_query_set_caps_result (query, caps);
gst_caps_unref (caps);
return TRUE;
}
static gboolean
gst_gl_stereo_mix_src_query (GstAggregator * agg, GstQuery * query)
{
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CAPS:
return gst_gl_stereo_mix_query_caps (agg->srcpad, agg, query);
break;
default:
break;
}
return GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
}
static GstFlowReturn
gst_gl_stereo_mix_create_output_buffer (GstVideoAggregator * videoaggregator,
GstBuffer ** outbuf)
{
GstGLStereoMix *mix = GST_GL_STEREO_MIX (videoaggregator);
GstFlowReturn ret = GST_FLOW_OK;
#if 0
if (!mix->priv->pool_active) {
if (!gst_buffer_pool_set_active (mix->priv->pool, TRUE)) {
GST_ELEMENT_ERROR (mix, RESOURCE, SETTINGS,
("failed to activate bufferpool"), ("failed to activate bufferpool"));
return GST_FLOW_ERROR;
}
mix->priv->pool_active = TRUE;
}
return gst_buffer_pool_acquire_buffer (mix->priv->pool, outbuf, NULL);
#endif
if (!gst_gl_stereo_mix_make_output (mix)) {
gst_buffer_replace (&mix->primary_out, NULL);
gst_buffer_replace (&mix->auxilliary_out, NULL);
GST_ELEMENT_ERROR (mix, RESOURCE, SETTINGS,
("Failed to generate output"), ("failed to generate output"));
ret = GST_FLOW_ERROR;
}
if (mix->auxilliary_out) {
*outbuf = mix->auxilliary_out;
mix->auxilliary_out = NULL;
} else {
*outbuf = mix->primary_out;
mix->primary_out = NULL;
}
return ret;
}
static gboolean
gst_gl_stereo_mix_make_output (GstGLStereoMix * mix)
{
GList *walk;
gboolean res = FALSE;
GstElement *element = GST_ELEMENT (mix);
gboolean missing_buffer = FALSE;
GST_LOG_OBJECT (mix, "Processing buffers");
GST_OBJECT_LOCK (mix);
walk = element->sinkpads;
while (walk) {
GstVideoAggregatorPad *vaggpad = walk->data;
GstGLStereoMixPad *pad = walk->data;
GstBuffer *buffer = gst_video_aggregator_pad_get_current_buffer (vaggpad);
GST_LOG_OBJECT (mix, "Checking pad %" GST_PTR_FORMAT, vaggpad);
if (buffer != NULL) {
pad->current_buffer = buffer;
GST_DEBUG_OBJECT (pad, "Got buffer %" GST_PTR_FORMAT,
pad->current_buffer);
} else {
GST_LOG_OBJECT (mix, "No buffer on pad %" GST_PTR_FORMAT, vaggpad);
pad->current_buffer = NULL;
missing_buffer = TRUE;
}
walk = g_list_next (walk);
}
if (missing_buffer) {
/* We're still waiting for a buffer to turn up on at least one input */
GST_WARNING_OBJECT (mix, "Not generating output - need more input buffers");
res = TRUE;
goto out;
}
/* Copy GL memory from each input frame to the output */
if (!gst_gl_stereo_mix_process_frames (mix)) {
GST_LOG_OBJECT (mix, "Failed to process frames to output");
goto out;
}
if (mix->primary_out == NULL)
goto out;
res = TRUE;
out:
GST_OBJECT_UNLOCK (mix);
return res;
}
static GstFlowReturn
gst_gl_stereo_mix_aggregate_frames (GstVideoAggregator * vagg,
GstBuffer * outbuf)
{
GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg);
/* If we're operating in frame-by-frame mode, push
* the primary view now, and let the parent class
* push the remaining auxilliary view */
if (GST_VIDEO_INFO_MULTIVIEW_MODE (&vagg->info) ==
GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
/* Transfer the timestamps video-agg put on the aux buffer */
gst_buffer_copy_into (mix->primary_out, outbuf,
GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
gst_aggregator_finish_buffer (GST_AGGREGATOR (vagg), mix->primary_out);
mix->primary_out = NULL;
/* And actually, we don't want timestamps on the aux buffer */
GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
}
return GST_FLOW_OK;
}
static void
gst_gl_stereo_mix_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstGLStereoMix *mix = GST_GL_STEREO_MIX (object);
switch (prop_id) {
case PROP_DOWNMIX_MODE:
g_value_set_enum (value, mix->downmix_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_stereo_mix_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstGLStereoMix *mix = GST_GL_STEREO_MIX (object);
switch (prop_id) {
case PROP_DOWNMIX_MODE:
mix->downmix_mode = g_value_get_enum (value);
if (mix->viewconvert)
g_object_set_property (G_OBJECT (mix->viewconvert), "downmix-mode",
value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstPad *
gst_gl_stereo_mix_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * req_name, const GstCaps * caps)
{
GstPad *newpad;
newpad = (GstPad *)
GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
templ, req_name, caps);
if (newpad == NULL)
goto could_not_create;
gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (newpad),
GST_OBJECT_NAME (newpad));
return GST_PAD_CAST (newpad);
could_not_create:
{
GST_DEBUG_OBJECT (element, "could not create/add pad");
return NULL;
}
}
static void
gst_gl_stereo_mix_release_pad (GstElement * element, GstPad * pad)
{
GST_DEBUG_OBJECT (element, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
gst_child_proxy_child_removed (GST_CHILD_PROXY (element), G_OBJECT (pad),
GST_OBJECT_NAME (pad));
GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad);
}
static gboolean
gst_gl_stereo_mix_start (GstAggregator * agg)
{
GstGLStereoMix *mix = GST_GL_STEREO_MIX (agg);
if (!GST_AGGREGATOR_CLASS (parent_class)->start (agg))
return FALSE;
GST_OBJECT_LOCK (mix);
mix->viewconvert = gst_gl_view_convert_new ();
g_object_set (G_OBJECT (mix->viewconvert), "downmix-mode",
mix->downmix_mode, NULL);
GST_OBJECT_UNLOCK (mix);
return TRUE;
}
static gboolean
gst_gl_stereo_mix_stop (GstAggregator * agg)
{
GstGLStereoMix *mix = GST_GL_STEREO_MIX (agg);
if (!GST_AGGREGATOR_CLASS (parent_class)->stop (agg))
return FALSE;
if (mix->viewconvert) {
gst_object_unref (mix->viewconvert);
mix->viewconvert = NULL;
}
return TRUE;
}
/* Convert to caps that can be accepted by this element... */
static GstCaps *
get_converted_caps (GstGLStereoMix * mix, GstCaps * caps)
{
#if 0
GstGLContext *context = GST_GL_BASE_MIXER (mix)->context;
GstCaps *result, *tmp;
GST_LOG_OBJECT (mix, "Converting caps %" GST_PTR_FORMAT, caps);
result = gst_gl_upload_transform_caps (context, GST_PAD_SINK, caps, NULL);
tmp = result;
GST_TRACE_OBJECT (mix, "transfer returned caps %" GST_PTR_FORMAT, tmp);
result =
gst_gl_color_convert_transform_caps (context, GST_PAD_SINK, tmp, NULL);
gst_caps_unref (tmp);
GST_TRACE_OBJECT (mix, "convert returned caps %" GST_PTR_FORMAT, tmp);
tmp = result;
result = gst_gl_view_convert_transform_caps (mix->viewconvert,
GST_PAD_SINK, tmp, NULL);
gst_caps_unref (tmp);
#else
GstCaps *result;
GST_LOG_OBJECT (mix, "Converting caps %" GST_PTR_FORMAT, caps);
result = gst_gl_view_convert_transform_caps (mix->viewconvert,
GST_PAD_SINK, caps, NULL);
#endif
GST_LOG_OBJECT (mix, "returning caps %" GST_PTR_FORMAT, result);
return result;
}
/* Return the possible output caps based on inputs and downstream prefs */
static GstCaps *
_update_caps (GstVideoAggregator * vagg, GstCaps * caps)
{
GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg);
GList *l;
gint best_width = -1, best_height = -1;
gdouble best_fps = -1, cur_fps;
gint best_fps_n = 0, best_fps_d = 1;
GstVideoInfo *mix_info;
GstCaps *blend_caps, *tmp_caps;
GstCaps *out_caps;
GST_OBJECT_LOCK (vagg);
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
GstVideoAggregatorPad *pad = l->data;
GstVideoInfo tmp = pad->info;
gint this_width, this_height;
gint fps_n, fps_d;
if (!pad->info.finfo)
continue;
/* This can happen if we release a pad and another pad hasn't been negotiated_caps yet */
if (GST_VIDEO_INFO_FORMAT (&pad->info) == GST_VIDEO_FORMAT_UNKNOWN)
continue;
/* Convert to per-view width/height for unpacked forms */
gst_video_multiview_video_info_change_mode (&tmp,
GST_VIDEO_MULTIVIEW_MODE_SEPARATED, GST_VIDEO_MULTIVIEW_FLAGS_NONE);
this_width = GST_VIDEO_INFO_WIDTH (&tmp);
this_height = GST_VIDEO_INFO_HEIGHT (&tmp);
fps_n = GST_VIDEO_INFO_FPS_N (&tmp);
fps_d = GST_VIDEO_INFO_FPS_D (&tmp);
GST_INFO_OBJECT (vagg, "Input pad %" GST_PTR_FORMAT
" w %u h %u", pad, this_width, this_height);
if (this_width == 0 || this_height == 0)
continue;
if (best_width < this_width)
best_width = this_width;
if (best_height < this_height)
best_height = this_height;
if (fps_d == 0)
cur_fps = 0.0;
else
gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
if (best_fps < cur_fps) {
best_fps = cur_fps;
best_fps_n = fps_n;
best_fps_d = fps_d;
}
/* FIXME: Preserve PAR for at least one input when different sized inputs */
}
GST_OBJECT_UNLOCK (vagg);
mix_info = &mix->mix_info;
gst_video_info_set_format (mix_info, GST_VIDEO_FORMAT_RGBA, best_width,
best_height);
GST_VIDEO_INFO_FPS_N (mix_info) = best_fps_n;
GST_VIDEO_INFO_FPS_D (mix_info) = best_fps_d;
GST_VIDEO_INFO_MULTIVIEW_MODE (mix_info) = GST_VIDEO_MULTIVIEW_MODE_SEPARATED;
GST_VIDEO_INFO_VIEWS (mix_info) = 2;
/* FIXME: If input is marked as flipped or flopped, preserve those flags */
GST_VIDEO_INFO_MULTIVIEW_FLAGS (mix_info) = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
/* Choose our output format based on downstream preferences */
blend_caps = gst_video_info_to_caps (mix_info);
gst_caps_set_features (blend_caps, 0,
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY));
tmp_caps = get_converted_caps (GST_GL_STEREO_MIX (vagg), blend_caps);
gst_caps_unref (blend_caps);
out_caps = gst_caps_intersect (caps, tmp_caps);
gst_caps_unref (tmp_caps);
GST_DEBUG_OBJECT (vagg, "Possible output caps %" GST_PTR_FORMAT, out_caps);
return out_caps;
}
/* Called after videoaggregator fixates our caps */
static gboolean
_negotiated_caps (GstAggregator * agg, GstCaps * caps)
{
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg);
GstCaps *in_caps;
GST_LOG_OBJECT (mix, "Configured output caps %" GST_PTR_FORMAT, caps);
if (GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps)
if (!GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps))
return FALSE;
/* Update the glview_convert output */
/* We can configure the view_converter now */
gst_gl_view_convert_set_context (mix->viewconvert,
GST_GL_BASE_MIXER (mix)->context);
in_caps = gst_video_info_to_caps (&mix->mix_info);
gst_caps_set_features (in_caps, 0,
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY));
gst_caps_set_simple (in_caps, "texture-target", G_TYPE_STRING,
GST_GL_TEXTURE_TARGET_2D_STR, NULL);
gst_gl_view_convert_set_caps (mix->viewconvert, in_caps, caps);
return TRUE;
}
/* called with the object lock held */
static gboolean
gst_gl_stereo_mix_process_frames (GstGLStereoMix * mixer)
{
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mixer);
GstBuffer *converted_buffer, *inbuf;
GstVideoInfo *out_info = &vagg->info;
#ifndef G_DISABLE_ASSERT
gint n;
#endif
gint v, views;
gint valid_views = 0;
GList *walk;
inbuf = gst_buffer_new ();
walk = GST_ELEMENT (mixer)->sinkpads;
while (walk) {
GstGLStereoMixPad *pad = walk->data;
GstMemory *in_mem;
GST_LOG_OBJECT (mixer, "Handling frame %d", valid_views);
if (!pad || !pad->current_buffer) {
GST_DEBUG ("skipping texture, null frame");
walk = g_list_next (walk);
continue;
}
in_mem = gst_buffer_get_memory (pad->current_buffer, 0);
GST_LOG_OBJECT (mixer,
"Appending memory %" GST_PTR_FORMAT " to intermediate buffer", in_mem);
/* Appending the memory to a 2nd buffer locks it
* exclusive a 2nd time, which will mark it for
* copy-on-write. The ref will keep the memory
* alive but we add a parent_buffer_meta to also
* prevent the input buffer from returning to any buffer
* pool it might belong to
*/
gst_buffer_append_memory (inbuf, in_mem);
/* Use parent buffer meta to keep input buffer alive */
gst_buffer_add_parent_buffer_meta (inbuf, pad->current_buffer);
valid_views++;
walk = g_list_next (walk);
}
if (mixer->mix_info.views != valid_views) {
GST_WARNING_OBJECT (mixer, "Not enough input views to process");
return FALSE;
}
if (GST_VIDEO_INFO_MULTIVIEW_MODE (out_info) ==
GST_VIDEO_MULTIVIEW_MODE_SEPARATED)
views = out_info->views;
else
views = 1;
if (gst_gl_view_convert_submit_input_buffer (mixer->viewconvert,
FALSE, inbuf) != GST_FLOW_OK)
return FALSE;
/* Clear any existing buffers, just in case */
gst_buffer_replace (&mixer->primary_out, NULL);
gst_buffer_replace (&mixer->auxilliary_out, NULL);
if (gst_gl_view_convert_get_output (mixer->viewconvert,
&mixer->primary_out) != GST_FLOW_OK)
return FALSE;
if (GST_VIDEO_INFO_MULTIVIEW_MODE (out_info) ==
GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME) {
if (gst_gl_view_convert_get_output (mixer->viewconvert,
&mixer->auxilliary_out) != GST_FLOW_OK)
return FALSE;
}
if (mixer->primary_out == NULL)
return FALSE;
converted_buffer = mixer->primary_out;
#ifndef G_DISABLE_ASSERT
n = gst_buffer_n_memory (converted_buffer);
g_assert (n == GST_VIDEO_INFO_N_PLANES (out_info) * views);
#endif
for (v = 0; v < views; v++) {
gst_buffer_add_video_meta_full (converted_buffer, v,
GST_VIDEO_INFO_FORMAT (out_info),
GST_VIDEO_INFO_WIDTH (out_info),
GST_VIDEO_INFO_HEIGHT (out_info),
GST_VIDEO_INFO_N_PLANES (out_info), out_info->offset, out_info->stride);
if (mixer->auxilliary_out) {
gst_buffer_add_video_meta_full (mixer->auxilliary_out, v,
GST_VIDEO_INFO_FORMAT (out_info),
GST_VIDEO_INFO_WIDTH (out_info),
GST_VIDEO_INFO_HEIGHT (out_info),
GST_VIDEO_INFO_N_PLANES (out_info), out_info->offset,
out_info->stride);
}
}
return TRUE;
}
/* GstChildProxy implementation */
static GObject *
gst_gl_stereo_mix_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
guint index)
{
GstGLStereoMix *gl_stereo_mix = GST_GL_STEREO_MIX (child_proxy);
GObject *obj = NULL;
GST_OBJECT_LOCK (gl_stereo_mix);
obj = g_list_nth_data (GST_ELEMENT_CAST (gl_stereo_mix)->sinkpads, index);
if (obj)
gst_object_ref (obj);
GST_OBJECT_UNLOCK (gl_stereo_mix);
return obj;
}
static guint
gst_gl_stereo_mix_child_proxy_get_children_count (GstChildProxy * child_proxy)
{
guint count = 0;
GstGLStereoMix *gl_stereo_mix = GST_GL_STEREO_MIX (child_proxy);
GST_OBJECT_LOCK (gl_stereo_mix);
count = GST_ELEMENT_CAST (gl_stereo_mix)->numsinkpads;
GST_OBJECT_UNLOCK (gl_stereo_mix);
GST_INFO_OBJECT (gl_stereo_mix, "Children Count: %d", count);
return count;
}
static void
gst_gl_stereo_mix_child_proxy_init (gpointer g_iface, gpointer iface_data)
{
GstChildProxyInterface *iface = g_iface;
iface->get_child_by_index = gst_gl_stereo_mix_child_proxy_get_child_by_index;
iface->get_children_count = gst_gl_stereo_mix_child_proxy_get_children_count;
}

View file

@ -1,87 +0,0 @@
/*
* GStreamer
* Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
* Copyright (C) 2014 Jan Schmidt <jan@noraisin.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* 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_STEREO_MIX_H__
#define __GST_GL_STEREO_MIX_H__
#include "gstglmixer.h"
G_BEGIN_DECLS
#define GST_TYPE_GL_STEREO_MIX (gst_gl_stereo_mix_get_type())
#define GST_GL_STEREO_MIX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_STEREO_MIX, GstGLStereoMix))
#define GST_GL_STEREO_MIX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_STEREO_MIX, GstGLStereoMixClass))
#define GST_IS_GL_STEREO_MIX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_STEREO_MIX))
#define GST_IS_GL_STEREO_MIX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_STEREO_MIX))
#define GST_GL_STEREO_MIX_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_GL_STEREO_MIX,GstGLStereoMixClass))
typedef struct _GstGLStereoMix GstGLStereoMix;
typedef struct _GstGLStereoMixClass GstGLStereoMixClass;
typedef struct _GstGLStereoMixPad GstGLStereoMixPad;
typedef struct _GstGLStereoMixPadClass GstGLStereoMixPadClass;
struct _GstGLStereoMixPad
{
GstGLMixerPad mixer_pad;
gboolean mapped;
GstBuffer *current_buffer;
};
struct _GstGLStereoMixPadClass
{
GstGLMixerPadClass mixer_pad_class;
};
#define GST_TYPE_GL_STEREO_MIX_PAD (gst_gl_stereo_mix_pad_get_type ())
GType gst_gl_stereo_mix_pad_get_type (void);
struct _GstGLStereoMix
{
GstGLMixer mixer;
GLuint out_tex_id;
GstGLViewConvert *viewconvert;
GstGLStereoDownmix downmix_mode;
GstVideoInfo mix_info;
GPtrArray *input_frames;
GstBuffer *primary_out;
GstBuffer *auxilliary_out;
};
struct _GstGLStereoMixClass
{
GstGLMixerClass mixer_class;
};
GType gst_gl_stereo_mix_get_type(void);
G_END_DECLS
#endif /* __GST_GL_STEREO_MIX_H__ */

View file

@ -1,178 +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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglfuncs.h>
#include "gstglutils.h"
struct _compile_shader
{
GstGLShader **shader;
const gchar *vertex_src;
const gchar *fragment_src;
};
static void
_compile_shader (GstGLContext * context, struct _compile_shader *data)
{
GstGLShader *shader;
GstGLSLStage *vert, *frag;
GError *error = NULL;
shader = gst_gl_shader_new (context);
if (data->vertex_src) {
vert = gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, data->vertex_src);
if (!gst_glsl_stage_compile (vert, &error)) {
GST_ERROR_OBJECT (vert, "%s", error->message);
gst_object_unref (vert);
gst_object_unref (shader);
return;
}
if (!gst_gl_shader_attach (shader, vert)) {
gst_object_unref (shader);
return;
}
}
if (data->fragment_src) {
frag = gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
data->fragment_src);
if (!gst_glsl_stage_compile (frag, &error)) {
GST_ERROR_OBJECT (frag, "%s", error->message);
gst_object_unref (frag);
gst_object_unref (shader);
return;
}
if (!gst_gl_shader_attach (shader, frag)) {
gst_object_unref (shader);
return;
}
}
if (!gst_gl_shader_link (shader, &error)) {
GST_ERROR_OBJECT (shader, "%s", error->message);
g_error_free (error);
error = NULL;
gst_gl_context_clear_shader (context);
gst_object_unref (shader);
return;
}
*data->shader = shader;
}
/* Called by glfilter */
gboolean
gst_gl_context_gen_shader (GstGLContext * context, const gchar * vert_src,
const gchar * frag_src, GstGLShader ** shader)
{
struct _compile_shader data;
g_return_val_if_fail (frag_src != NULL || vert_src != NULL, FALSE);
g_return_val_if_fail (shader != NULL, FALSE);
data.shader = shader;
data.vertex_src = vert_src;
data.fragment_src = frag_src;
gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _compile_shader,
&data);
return *shader != NULL;
}
static const gfloat identity_matrix[] = {
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,
};
static const gfloat from_ndc_matrix[] = {
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0,
};
static const gfloat to_ndc_matrix[] = {
2.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0,
-1.0, -1.0, -1.0, 1.0,
};
void
gst_gl_multiply_matrix4 (const gfloat * a, const gfloat * b, gfloat * result)
{
int i, j, k;
gfloat tmp[16] = { 0.0f };
if (!a || !b || !result)
return;
for (i = 0; i < 4; i++) { /* column */
for (j = 0; j < 4; j++) { /* row */
for (k = 0; k < 4; k++) {
tmp[j + (i * 4)] += a[k + (i * 4)] * b[j + (k * 4)];
}
}
}
for (i = 0; i < 16; i++)
result[i] = tmp[i];
}
void gst_gl_get_affine_transformation_meta_as_ndc_ext
(GstVideoAffineTransformationMeta * meta, gfloat * matrix)
{
if (!meta) {
int i;
for (i = 0; i < 16; i++) {
matrix[i] = identity_matrix[i];
}
} else {
float tmp[16];
gst_gl_multiply_matrix4 (from_ndc_matrix, meta->matrix, tmp);
gst_gl_multiply_matrix4 (tmp, to_ndc_matrix, matrix);
}
}
void gst_gl_set_affine_transformation_meta_from_ndc_ext
(GstVideoAffineTransformationMeta * meta, const gfloat * matrix)
{
float tmp[16];
g_return_if_fail (meta != NULL);
gst_gl_multiply_matrix4 (to_ndc_matrix, matrix, tmp);
gst_gl_multiply_matrix4 (tmp, from_ndc_matrix, meta->matrix);
}

View file

@ -1,38 +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 __EXT_GL_GST_GL_UTILS_H__
#define __EXT_GL_GST_GL_UTILS_H__
#include <gst/gl/gl.h>
G_BEGIN_DECLS
gboolean gst_gl_context_gen_shader (GstGLContext * context,
const gchar * shader_vertex_source,
const gchar * shader_fragment_source, GstGLShader ** shader);
void gst_gl_multiply_matrix4 (const gfloat * a, const gfloat * b, gfloat * result);
void gst_gl_get_affine_transformation_meta_as_ndc_ext (GstVideoAffineTransformationMeta *
meta, gfloat * matrix);
void gst_gl_set_affine_transformation_meta_from_ndc_ext (GstVideoAffineTransformationMeta * meta, const gfloat * matrix);
G_END_DECLS
#endif /* __EXT_GL_GST_GL_UTILS_H__ */

File diff suppressed because it is too large Load diff

View file

@ -1,143 +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_VIDEO_MIXER_H_
#define _GST_GL_VIDEO_MIXER_H_
#include "gstglmixer.h"
G_BEGIN_DECLS
#define GST_TYPE_GL_VIDEO_MIXER (gst_gl_video_mixer_get_type())
#define GST_GL_VIDEO_MIXER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixer))
#define GST_IS_GL_VIDEO_MIXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_VIDEO_MIXER))
#define GST_GL_VIDEO_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixerClass))
#define GST_IS_GL_VIDEO_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_VIDEO_MIXER))
#define GST_GL_VIDEO_MIXER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixerClass))
typedef struct _GstGLVideoMixer GstGLVideoMixer;
typedef struct _GstGLVideoMixerClass GstGLVideoMixerClass;
/**
* GstGLVideoMixerBackground:
* @GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER: checker pattern background
* @GST_GL_VIDEO_MIXER_BACKGROUND_BLACK: solid color black background
* @GST_GL_VIDEO_MIXER_BACKGROUND_WHITE: solid color white background
* @GST_GL_VIDEO_MIXER_BACKGROUND_TRANSPARENT: background is left transparent and layers are composited using "A OVER B" composition rules. This is only applicable to AYUV and ARGB (and variants) as it preserves the alpha channel and allows for further mixing.
*
* The different backgrounds compositor can blend over.
*/
typedef enum
{
GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER,
GST_GL_VIDEO_MIXER_BACKGROUND_BLACK,
GST_GL_VIDEO_MIXER_BACKGROUND_WHITE,
GST_GL_VIDEO_MIXER_BACKGROUND_TRANSPARENT,
}
GstGLVideoMixerBackground;
/**
* GstGLVideoMixerBlendEquation:
* @GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD: Add the two results.
* @GST_GL_VIDEO_MIXER_BLEND_EQUATION_SUBTRACT: Subtract component-wise the destination from the source (S - D).
* @GST_GL_VIDEO_MIXER_BLEND_EQUATION_REVERSE_SUBTRACT: Subtract component-wise the source from the destination (D - S).
*
* The blending equation to use. See the opengl specificition for
* glBlendEquationSeparate
*/
typedef enum
{
GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD,
GST_GL_VIDEO_MIXER_BLEND_EQUATION_SUBTRACT,
GST_GL_VIDEO_MIXER_BLEND_EQUATION_REVERSE_SUBTRACT,
}
GstGLVideoMixerBlendEquation;
/**
* GstGLVideoMixerBlendFunction:
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ZERO: All components are zero
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE: All components are one
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_COLOR: Use the source color/alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_COLOR: One minus the source color/alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_COLOR: Use the destination color/alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_COLOR: One minus the destination color/alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA: All components are the source alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA: All components are one minus the source alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_ALPHA: All components are the destination alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_ALPHA: All components are one minus the destination alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_COLOR: Use the constant color/alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_COLOR: Use one minus the constant color/alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_ALPHA: All components are the constant alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_COLOR: All components are one minus the constant alpha
* @GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE: All color components
* are the minimum of source alpha and one minus the destination alpha.
* Alpha is equal to one.
*
* The blending function to use. See the opengl specificition for
* glBlendFuncSeparate
*/
typedef enum
{
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ZERO,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_COLOR,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_COLOR,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_COLOR,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_COLOR,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_ALPHA,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_ALPHA,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_COLOR,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_COLOR,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_ALPHA,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_ALPHA,
GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE,
}
GstGLVideoMixerBlendFunction;
struct _GstGLVideoMixer
{
GstGLMixer mixer;
GstGLVideoMixerBackground background;
GstGLShader *shader;
GstGLShader *checker;
GLuint vao;
GLuint vbo_indices;
GLuint checker_vbo;
GstGLMemory *out_tex;
gboolean output_geo_change;
};
struct _GstGLVideoMixerClass
{
GstGLMixerClass mixer_class;
};
GType gst_gl_video_mixer_get_type (void);
GType gst_gl_video_mixer_bin_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERCUBE_H_ */

View file

@ -1,112 +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>
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:plugin-openglmixers
* @title: OpenGL Mixers
*
* 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.
|[
* GST_DEBUG=gl*:6 gst-launch-1.0 videotestsrc ! glimagesink
* ]| A debugging pipelines related to shaders.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglmixerbin.h"
#include "gstglvideomixer.h"
#include "gstglstereomix.h"
#if GST_GL_HAVE_OPENGL
#include "gstglmosaic.h"
#endif /* GST_GL_HAVE_OPENGL */
#if GST_GL_HAVE_WINDOW_DISPMANX
extern void bcm_host_init (void);
#endif
#if GST_GL_HAVE_WINDOW_X11
#include <X11/Xlib.h>
#endif
GST_DEBUG_CATEGORY_STATIC (glmixers_debug);
#define GST_CAT_DEFAULT glmixers_debug
static gboolean
plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (glmixers_debug, "openglmixers", 0, "OpenGL Mixers");
#if GST_GL_HAVE_WINDOW_DISPMANX
GST_DEBUG ("Initialize BCM host");
bcm_host_init ();
#endif
#if GST_GL_HAVE_WINDOW_X11
if (g_getenv ("GST_GL_XINITTHREADS"))
XInitThreads ();
#endif
if (!gst_element_register (plugin, "glmixerbin",
GST_RANK_NONE, GST_TYPE_GL_MIXER_BIN)) {
return FALSE;
}
if (!gst_element_register (plugin, "glvideomixer",
GST_RANK_NONE, gst_gl_video_mixer_bin_get_type ())) {
return FALSE;
}
if (!gst_element_register (plugin, "glvideomixerelement",
GST_RANK_NONE, gst_gl_video_mixer_get_type ())) {
return FALSE;
}
if (!gst_element_register (plugin, "glstereomix",
GST_RANK_NONE, GST_TYPE_GL_STEREO_MIX)) {
return FALSE;
}
#if GST_GL_HAVE_OPENGL
if (!gst_element_register (plugin, "glmosaic",
GST_RANK_NONE, GST_TYPE_GL_MOSAIC)) {
return FALSE;
}
#endif /* GST_GL_HAVE_OPENGL */
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
openglmixers,
"OpenGL mixers",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,36 +0,0 @@
opengl_sources = [
'gstopengl.c',
'gstglbasemixer.c',
'gstglmixerbin.c',
'gstglmixer.c',
'gstglvideomixer.c',
'gstglstereomix.c',
'gstglutils.c',
]
if gstgl_dep.found()
optional_deps = []
if gst_gl_have_api_opengl # have desktop GL
opengl_sources += [
'gstglmosaic.c',
]
endif
if x11_dep.found()
# for XInitThreads()
optional_deps += x11_dep
endif
gstopenglmixers = library('gstopenglmixers',
opengl_sources,
c_args : gst_plugins_bad_args,
link_args : noseh_link_args,
include_directories : [configinc],
dependencies : [gstgl_dep, gstvideo_dep,
gstbase_dep, gstcontroller_dep, libm] + optional_deps,
install : true,
install_dir : plugins_install_dir,
)
pkgconfig.generate(gstopenglmixers, install_dir : plugins_pkgconfig_install_dir)
endif

View file

@ -15,7 +15,6 @@ subdir('faad')
subdir('fdkaac')
subdir('flite')
subdir('fluidsynth')
subdir('gl')
subdir('gme')
subdir('gsm')
subdir('hls')

View file

@ -97,7 +97,7 @@ option('fbdev', type : 'feature', value : 'auto', description : 'Framebuffer vid
option('fdkaac', type : 'feature', value : 'auto', description : 'Fraunhofer AAC audio codec plugin')
option('flite', type : 'feature', value : 'auto', description : 'Flite speech synthesizer source plugin')
option('fluidsynth', type : 'feature', value : 'auto', description : 'Fluidsynth MIDI decoder plugin')
option('gl', type : 'feature', value : 'auto', description : 'GStreamer OpenGL mixer plugin')
option('gl', type : 'feature', value : 'auto', description : 'GStreamer OpenGL integration support (used by various plugins)')
option('gme', type : 'feature', value : 'auto', description : 'libgme gaming console music file decoder plugin')
option('gsm', type : 'feature', value : 'auto', description : 'GSM encoder/decoder plugin')
option('ipcpipeline', type : 'feature', value : 'auto', description : 'Inter-process communication plugin')