mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +00:00
Remove openglmixers plugin, moved to -base
Merged into the existing opengl plugin in -base.
This commit is contained in:
parent
e42efbccb1
commit
88683e5a1e
28 changed files with 1 additions and 7075 deletions
|
@ -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
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 <matthew@centricular.com></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 <julien.isorce@gmail.com></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 <jan@centricular.com></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 <matthew@centricular.com></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 <matthew@centricular.com></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>
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
|
@ -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
|
@ -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_ */
|
|
@ -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)
|
|
@ -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
|
|
@ -15,7 +15,6 @@ subdir('faad')
|
|||
subdir('fdkaac')
|
||||
subdir('flite')
|
||||
subdir('fluidsynth')
|
||||
subdir('gl')
|
||||
subdir('gme')
|
||||
subdir('gsm')
|
||||
subdir('hls')
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in a new issue