mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-04 22:48:54 +00:00
selector: move input-selector and output-selector to core
https://bugzilla.gnome.org/show_bug.cgi?id=614306
This commit is contained in:
parent
44946440a2
commit
c6c3d9781b
28 changed files with 11 additions and 3359 deletions
|
@ -50,14 +50,18 @@ CRUFT_FILES = \
|
|||
$(top_builddir)/gst/amrparse/.libs/*.{so,dll,DLL,dylib} \
|
||||
$(top_builddir)/gst/flacparse/.libs/*.{so,dll,DLL,dylib} \
|
||||
$(top_builddir)/gst/imagefreeze/.libs/*.{so,dll,DLL,dylib} \
|
||||
$(top_builddir)/gst/selector/.libs/*.{so,dll,DLL,dylib} \
|
||||
$(top_builddir)/gst/shapewipe/.libs/*.{so,dll,DLL,dylib} \
|
||||
$(top_builddir)/gst/valve/.libs/*.{so,dll,DLL,dylib} \
|
||||
$(top_builddir)/sys/oss4/.libs/*.{so,dll,DLL,dylib} \
|
||||
$(top_builddir)/tests/check/elements/autocolorspace \
|
||||
$(top_builddir)/tests/check/elements/capssetter \
|
||||
$(top_builddir)/tests/check/elements/imagefreeze \
|
||||
$(top_builddir)/tests/check/elements/selector \
|
||||
$(top_builddir)/tests/check/elements/valve \
|
||||
$(top_builddir)/tests/check/pipelines/metadata \
|
||||
$(top_builddir)/tests/examples/switch/switcher \
|
||||
$(top_builddir)/tests/icles/output-selector-test \
|
||||
$(top_builddir)/tests/icles/test-oss4
|
||||
|
||||
CRUFT_DIRS = \
|
||||
|
@ -65,9 +69,11 @@ CRUFT_DIRS = \
|
|||
$(top_srcdir)/gst/amrparse \
|
||||
$(top_srcdir)/gst/flacparse \
|
||||
$(top_srcdir)/gst/imagefreeze \
|
||||
$(top_srcdir)/gst/selector \
|
||||
$(top_srcdir)/gst/shapewipe \
|
||||
$(top_srcdir)/gst/valve \
|
||||
$(top_srcdir)/tests/examples/shapewipe \
|
||||
$(top_srcdir)/tests/examples/switch \
|
||||
$(top_srcdir)/ext/alsaspdif \
|
||||
$(top_srcdir)/ext/ivorbis \
|
||||
$(top_srcdir)/ext/metadata
|
||||
|
|
|
@ -337,7 +337,6 @@ AG_GST_CHECK_PLUGIN(rtpmux)
|
|||
AG_GST_CHECK_PLUGIN(scaletempo)
|
||||
AG_GST_CHECK_PLUGIN(sdp)
|
||||
AG_GST_CHECK_PLUGIN(segmentclip)
|
||||
AG_GST_CHECK_PLUGIN(selector)
|
||||
AG_GST_CHECK_PLUGIN(siren)
|
||||
AG_GST_CHECK_PLUGIN(speed)
|
||||
AG_GST_CHECK_PLUGIN(subenc)
|
||||
|
@ -1766,7 +1765,6 @@ gst/rtpmux/Makefile
|
|||
gst/scaletempo/Makefile
|
||||
gst/sdp/Makefile
|
||||
gst/segmentclip/Makefile
|
||||
gst/selector/Makefile
|
||||
gst/siren/Makefile
|
||||
gst/speed/Makefile
|
||||
gst/subenc/Makefile
|
||||
|
@ -1814,7 +1812,6 @@ tests/examples/camerabin2/Makefile
|
|||
tests/examples/directfb/Makefile
|
||||
tests/examples/mxf/Makefile
|
||||
tests/examples/scaletempo/Makefile
|
||||
tests/examples/switch/Makefile
|
||||
tests/examples/jack/Makefile
|
||||
tests/icles/Makefile
|
||||
ext/amrwbenc/Makefile
|
||||
|
|
|
@ -195,8 +195,6 @@ EXTRA_HFILES = \
|
|||
$(top_srcdir)/gst/rtpmux/gstrtpdtmfmux.h \
|
||||
$(top_srcdir)/gst/scaletempo/gstscaletempo.h \
|
||||
$(top_srcdir)/gst/sdp/gstsdpdemux.h \
|
||||
$(top_srcdir)/gst/selector/gstinputselector.h \
|
||||
$(top_srcdir)/gst/selector/gstoutputselector.h \
|
||||
$(top_srcdir)/gst/speed/gstspeed.h \
|
||||
$(top_srcdir)/gst/stereo/gststereo.h \
|
||||
$(top_srcdir)/gst/videomaxrate/videomaxrate.h \
|
||||
|
|
|
@ -68,7 +68,6 @@
|
|||
<xi:include href="xml/element-fpsdisplaysink.xml" />
|
||||
<xi:include href="xml/element-freeze.xml" />
|
||||
<xi:include href="xml/element-gaussianblur.xml" />
|
||||
<xi:include href="xml/element-input-selector.xml" />
|
||||
<xi:include href="xml/element-ivfparse.xml" />
|
||||
<xi:include href="xml/element-jackaudiosrc.xml" />
|
||||
<xi:include href="xml/element-jackaudiosink.xml" />
|
||||
|
@ -93,7 +92,6 @@
|
|||
<xi:include href="xml/element-mxfdemux.xml" />
|
||||
<xi:include href="xml/element-mxfmux.xml" />
|
||||
<xi:include href="xml/element-nuvdemux.xml" />
|
||||
<xi:include href="xml/element-output-selector.xml" />
|
||||
<xi:include href="xml/element-pcapparse.xml" />
|
||||
<xi:include href="xml/element-pinch.xml" />
|
||||
<xi:include href="xml/element-pyramidsegment.xml" />
|
||||
|
@ -204,7 +202,6 @@
|
|||
<xi:include href="xml/plugin-scaletempo.xml" />
|
||||
<xi:include href="xml/plugin-sdl.xml" />
|
||||
<xi:include href="xml/plugin-sdp.xml" />
|
||||
<xi:include href="xml/plugin-selector.xml" />
|
||||
<xi:include href="xml/plugin-shm.xml" />
|
||||
<xi:include href="xml/plugin-sndfile.xml" />
|
||||
<xi:include href="xml/plugin-soundtouch.xml" />
|
||||
|
|
|
@ -791,26 +791,6 @@ gauss_blur_get_type
|
|||
gst_gauss_blur_plugin_init
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>element-input-selector</FILE>
|
||||
<TITLE>input-selector</TITLE>
|
||||
GstInputSelector
|
||||
<SUBSECTION Standard>
|
||||
GstInputSelectorClass
|
||||
GST_INPUT_SELECTOR
|
||||
GST_INPUT_SELECTOR_CLASS
|
||||
GST_IS_INPUT_SELECTOR
|
||||
GST_IS_INPUT_SELECTOR_CLASS
|
||||
GST_TYPE_INPUT_SELECTOR
|
||||
gst_input_selector_get_type
|
||||
GST_INPUT_SELECTOR_BROADCAST
|
||||
GST_INPUT_SELECTOR_GET_COND
|
||||
GST_INPUT_SELECTOR_GET_LOCK
|
||||
GST_INPUT_SELECTOR_LOCK
|
||||
GST_INPUT_SELECTOR_UNLOCK
|
||||
GST_INPUT_SELECTOR_WAIT
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>element-ivfparse</FILE>
|
||||
<TITLE>ivfparse</TITLE>
|
||||
|
@ -1179,20 +1159,6 @@ GST_TYPE_NUV_DEMUX
|
|||
gst_nuv_demux_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>element-output-selector</FILE>
|
||||
<TITLE>output-selector</TITLE>
|
||||
GstOutputSelector
|
||||
<SUBSECTION Standard>
|
||||
GstOutputSelectorClass
|
||||
GST_OUTPUT_SELECTOR
|
||||
GST_OUTPUT_SELECTOR_CLASS
|
||||
GST_IS_OUTPUT_SELECTOR
|
||||
GST_IS_OUTPUT_SELECTOR_CLASS
|
||||
GST_TYPE_OUTPUT_SELECTOR
|
||||
gst_output_selector_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>element-pcapparse</FILE>
|
||||
<TITLE>pcapparse</TITLE>
|
||||
|
|
|
@ -18473,56 +18473,6 @@
|
|||
<DEFAULT>26</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstInputSelector::active-pad</NAME>
|
||||
<TYPE>GstPad*</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Active pad</NICK>
|
||||
<BLURB>The currently active sink pad.</BLURB>
|
||||
<DEFAULT></DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstInputSelector::n-pads</NAME>
|
||||
<TYPE>guint</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>r</FLAGS>
|
||||
<NICK>Number of Pads</NICK>
|
||||
<BLURB>The number of sink pads.</BLURB>
|
||||
<DEFAULT>0</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstInputSelector::select-all</NAME>
|
||||
<TYPE>gboolean</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Select all mode</NICK>
|
||||
<BLURB>Forwards data from all input pads.</BLURB>
|
||||
<DEFAULT>FALSE</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstOutputSelector::active-pad</NAME>
|
||||
<TYPE>GstPad*</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Active pad</NICK>
|
||||
<BLURB>Currently active src pad.</BLURB>
|
||||
<DEFAULT></DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstOutputSelector::resend-latest</NAME>
|
||||
<TYPE>gboolean</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Resend latest buffer</NICK>
|
||||
<BLURB>Resend latest buffer after a switch to a new pad.</BLURB>
|
||||
<DEFAULT>FALSE</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstGLTestSrc::is-live</NAME>
|
||||
<TYPE>gboolean</TYPE>
|
||||
|
@ -23453,16 +23403,6 @@
|
|||
<DEFAULT>-1</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstValve::drop</NAME>
|
||||
<TYPE>gboolean</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Drops all buffers if TRUE</NICK>
|
||||
<BLURB>If this property if TRUE, the element will drop all buffers, if its FALSE, it will let them through.</BLURB>
|
||||
<DEFAULT>FALSE</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstAutoConvert::factories</NAME>
|
||||
<TYPE>gpointer</TYPE>
|
||||
|
@ -28653,146 +28593,6 @@
|
|||
<DEFAULT>FALSE</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpBin::do-lost</NAME>
|
||||
<TYPE>gboolean</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Do Lost</NICK>
|
||||
<BLURB>Send an event downstream when a packet is lost.</BLURB>
|
||||
<DEFAULT>FALSE</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpBin::latency</NAME>
|
||||
<TYPE>guint</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Buffer latency in ms</NICK>
|
||||
<BLURB>Default amount of ms to buffer in the jitterbuffers.</BLURB>
|
||||
<DEFAULT>200</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpBin::sdes</NAME>
|
||||
<TYPE>GstStructure*</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>SDES</NICK>
|
||||
<BLURB>The SDES items of this session.</BLURB>
|
||||
<DEFAULT></DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpJitterBuffer::do-lost</NAME>
|
||||
<TYPE>gboolean</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Do Lost</NICK>
|
||||
<BLURB>Send an event downstream when a packet is lost.</BLURB>
|
||||
<DEFAULT>FALSE</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpJitterBuffer::drop-on-latency</NAME>
|
||||
<TYPE>gboolean</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Drop buffers when maximum latency is reached</NICK>
|
||||
<BLURB>Tells the jitterbuffer to never exceed the given latency in size.</BLURB>
|
||||
<DEFAULT>FALSE</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpJitterBuffer::latency</NAME>
|
||||
<TYPE>guint</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Buffer latency in ms</NICK>
|
||||
<BLURB>Amount of ms to buffer.</BLURB>
|
||||
<DEFAULT>200</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpJitterBuffer::ts-offset</NAME>
|
||||
<TYPE>gint64</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Timestamp Offset</NICK>
|
||||
<BLURB>Adjust buffer timestamps with offset in nanoseconds.</BLURB>
|
||||
<DEFAULT>0</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpSession::bandwidth</NAME>
|
||||
<TYPE>gdouble</TYPE>
|
||||
<RANGE>>= 0</RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>Bandwidth</NICK>
|
||||
<BLURB>The bandwidth of the session.</BLURB>
|
||||
<DEFAULT>64000</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpSession::internal-session</NAME>
|
||||
<TYPE>RTPSession*</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>r</FLAGS>
|
||||
<NICK>Internal Session</NICK>
|
||||
<BLURB>The internal RTPSession object.</BLURB>
|
||||
<DEFAULT></DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpSession::ntp-ns-base</NAME>
|
||||
<TYPE>guint64</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>NTP base time</NICK>
|
||||
<BLURB>The NTP base time corresponding to running_time 0.</BLURB>
|
||||
<DEFAULT>0</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpSession::num-active-sources</NAME>
|
||||
<TYPE>guint</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>r</FLAGS>
|
||||
<NICK>Num Active Sources</NICK>
|
||||
<BLURB>The number of active sources in the session.</BLURB>
|
||||
<DEFAULT>0</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpSession::num-sources</NAME>
|
||||
<TYPE>guint</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>r</FLAGS>
|
||||
<NICK>Num Sources</NICK>
|
||||
<BLURB>The number of sources in the session.</BLURB>
|
||||
<DEFAULT>0</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpSession::rtcp-fraction</NAME>
|
||||
<TYPE>gdouble</TYPE>
|
||||
<RANGE>>= 0</RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>RTCP Fraction</NICK>
|
||||
<BLURB>The fraction of the bandwidth used for RTCP.</BLURB>
|
||||
<DEFAULT>3000</DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstRtpSession::sdes</NAME>
|
||||
<TYPE>GstStructure*</TYPE>
|
||||
<RANGE></RANGE>
|
||||
<FLAGS>rw</FLAGS>
|
||||
<NICK>SDES</NICK>
|
||||
<BLURB>The SDES items of this session.</BLURB>
|
||||
<DEFAULT></DEFAULT>
|
||||
</ARG>
|
||||
|
||||
<ARG>
|
||||
<NAME>GstSSim::gauss-sigma</NAME>
|
||||
<TYPE>gfloat</TYPE>
|
||||
|
|
|
@ -223,7 +223,6 @@ GObject
|
|||
GstISMLMux
|
||||
GstId3BaseMux
|
||||
GstId3Mux
|
||||
GstInputSelector
|
||||
GstInterlace
|
||||
GstInvtelecine
|
||||
GstIvfParse
|
||||
|
@ -254,7 +253,6 @@ GObject
|
|||
GstMveMux
|
||||
GstNsfDec
|
||||
GstNuvDemux
|
||||
GstOutputSelector
|
||||
GstPcapParse
|
||||
GstPitch
|
||||
GstPnmdec
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
<plugin>
|
||||
<name>selector</name>
|
||||
<description>input/output stream selector elements</description>
|
||||
<filename>../../gst/selector/.libs/libgstselector.so</filename>
|
||||
<basename>libgstselector.so</basename>
|
||||
<version>0.10.20.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>input-selector</name>
|
||||
<longname>Input selector</longname>
|
||||
<class>Generic</class>
|
||||
<description>N-to-1 input stream selectoring</description>
|
||||
<author>Julien Moutte <julien@moutte.net>, Jan Schmidt <thaytan@mad.scientist.com>, Wim Taymans <wim.taymans@gmail.com></author>
|
||||
<pads>
|
||||
<caps>
|
||||
<name>sink%d</name>
|
||||
<direction>sink</direction>
|
||||
<presence>request</presence>
|
||||
<details>ANY</details>
|
||||
</caps>
|
||||
<caps>
|
||||
<name>src</name>
|
||||
<direction>source</direction>
|
||||
<presence>always</presence>
|
||||
<details>ANY</details>
|
||||
</caps>
|
||||
</pads>
|
||||
</element>
|
||||
<element>
|
||||
<name>output-selector</name>
|
||||
<longname>Output selector</longname>
|
||||
<class>Generic</class>
|
||||
<description>1-to-N output stream selectoring</description>
|
||||
<author>Stefan Kost <stefan.kost@nokia.com></author>
|
||||
<pads>
|
||||
<caps>
|
||||
<name>sink</name>
|
||||
<direction>sink</direction>
|
||||
<presence>always</presence>
|
||||
<details>ANY</details>
|
||||
</caps>
|
||||
<caps>
|
||||
<name>src%d</name>
|
||||
<direction>source</direction>
|
||||
<presence>request</presence>
|
||||
<details>ANY</details>
|
||||
</caps>
|
||||
</pads>
|
||||
</element>
|
||||
</elements>
|
||||
</plugin>
|
|
@ -95,7 +95,6 @@ rm -rf $RPM_BUILD_ROOT
|
|||
%{_libdir}/gstreamer-%{majorminor}/libgstmpeg4videoparse.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libgstfbdevsink.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libgstrawparse.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libgstselector.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libgstsubenc.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libresindvd.so
|
||||
%{_libdir}/gstreamer-%{majorminor}/libgstaiff.so
|
||||
|
|
2
gst/selector/.gitignore
vendored
2
gst/selector/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
gstselector-marshal.c
|
||||
gstselector-marshal.h
|
|
@ -1,24 +0,0 @@
|
|||
glib_gen_prefix = gst_selector
|
||||
glib_gen_basename = gstselector
|
||||
|
||||
include $(top_srcdir)/common/gst-glib-gen.mak
|
||||
|
||||
built_sources = gstselector-marshal.c
|
||||
built_headers = gstselector-marshal.h
|
||||
|
||||
BUILT_SOURCES = $(built_sources) $(built_headers)
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES)
|
||||
|
||||
EXTRA_DIST = gstselector-marshal.list
|
||||
|
||||
plugin_LTLIBRARIES = libgstselector.la
|
||||
|
||||
libgstselector_la_SOURCES = gstselector.c gstinputselector.c gstoutputselector.c
|
||||
nodist_libgstselector_la_SOURCES = $(built_sources)
|
||||
libgstselector_la_CFLAGS = $(GST_CFLAGS)
|
||||
libgstselector_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
|
||||
libgstselector_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstselector_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
|
||||
noinst_HEADERS = gstinputselector.h gstoutputselector.h
|
File diff suppressed because it is too large
Load diff
|
@ -1,84 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2003 Julien Moutte <julien@moutte.net>
|
||||
* Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||
* Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_INPUT_SELECTOR_H__
|
||||
#define __GST_INPUT_SELECTOR_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_INPUT_SELECTOR \
|
||||
(gst_input_selector_get_type())
|
||||
#define GST_INPUT_SELECTOR(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_INPUT_SELECTOR, GstInputSelector))
|
||||
#define GST_INPUT_SELECTOR_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_INPUT_SELECTOR, GstInputSelectorClass))
|
||||
#define GST_IS_INPUT_SELECTOR(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_INPUT_SELECTOR))
|
||||
#define GST_IS_INPUT_SELECTOR_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_INPUT_SELECTOR))
|
||||
|
||||
typedef struct _GstInputSelector GstInputSelector;
|
||||
typedef struct _GstInputSelectorClass GstInputSelectorClass;
|
||||
|
||||
#define GST_INPUT_SELECTOR_GET_LOCK(sel) (((GstInputSelector*)(sel))->lock)
|
||||
#define GST_INPUT_SELECTOR_GET_COND(sel) (((GstInputSelector*)(sel))->cond)
|
||||
#define GST_INPUT_SELECTOR_LOCK(sel) (g_mutex_lock (GST_INPUT_SELECTOR_GET_LOCK(sel)))
|
||||
#define GST_INPUT_SELECTOR_UNLOCK(sel) (g_mutex_unlock (GST_INPUT_SELECTOR_GET_LOCK(sel)))
|
||||
#define GST_INPUT_SELECTOR_WAIT(sel) (g_cond_wait (GST_INPUT_SELECTOR_GET_COND(sel), \
|
||||
GST_INPUT_SELECTOR_GET_LOCK(sel)))
|
||||
#define GST_INPUT_SELECTOR_BROADCAST(sel) (g_cond_broadcast (GST_INPUT_SELECTOR_GET_COND(sel)))
|
||||
|
||||
struct _GstInputSelector {
|
||||
GstElement element;
|
||||
|
||||
GstPad *srcpad;
|
||||
|
||||
GstPad *active_sinkpad;
|
||||
guint n_pads;
|
||||
guint padcount;
|
||||
|
||||
GstSegment segment; /* the output segment */
|
||||
gboolean pending_close; /* if we should push a close first */
|
||||
|
||||
GMutex *lock;
|
||||
GCond *cond;
|
||||
gboolean blocked;
|
||||
gboolean flushing;
|
||||
|
||||
/* select all mode, send data from all input pads forward */
|
||||
gboolean select_all;
|
||||
};
|
||||
|
||||
struct _GstInputSelectorClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
gint64 (*block) (GstInputSelector *self);
|
||||
void (*switch_) (GstInputSelector *self, GstPad *pad,
|
||||
gint64 stop_time, gint64 start_time);
|
||||
};
|
||||
|
||||
GType gst_input_selector_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_INPUT_SELECTOR_H__ */
|
|
@ -1,519 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:element-output-selector
|
||||
* @see_also: #GstOutputSelector, #GstInputSelector
|
||||
*
|
||||
* Direct input stream to one out of N output pads.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "gstoutputselector.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (output_selector_debug);
|
||||
#define GST_CAT_DEFAULT output_selector_debug
|
||||
|
||||
static GstStaticPadTemplate gst_output_selector_sink_factory =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
static GstStaticPadTemplate gst_output_selector_src_factory =
|
||||
GST_STATIC_PAD_TEMPLATE ("src%d",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_REQUEST,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_ACTIVE_PAD,
|
||||
PROP_RESEND_LATEST,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
#define _do_init(bla) \
|
||||
GST_DEBUG_CATEGORY_INIT (output_selector_debug, \
|
||||
"output-selector", 0, "An output stream selector element");
|
||||
|
||||
GST_BOILERPLATE_FULL (GstOutputSelector, gst_output_selector, GstElement,
|
||||
GST_TYPE_ELEMENT, _do_init);
|
||||
|
||||
static void gst_output_selector_dispose (GObject * object);
|
||||
static void gst_output_selector_set_property (GObject * object,
|
||||
guint prop_id, const GValue * value, GParamSpec * pspec);
|
||||
static void gst_output_selector_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec);
|
||||
static GstPad *gst_output_selector_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * unused);
|
||||
static void gst_output_selector_release_pad (GstElement * element,
|
||||
GstPad * pad);
|
||||
static GstFlowReturn gst_output_selector_chain (GstPad * pad, GstBuffer * buf);
|
||||
static GstFlowReturn gst_output_selector_buffer_alloc (GstPad * pad,
|
||||
guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
|
||||
static GstStateChangeReturn gst_output_selector_change_state (GstElement *
|
||||
element, GstStateChange transition);
|
||||
static gboolean gst_output_selector_handle_sink_event (GstPad * pad,
|
||||
GstEvent * event);
|
||||
|
||||
static void
|
||||
gst_output_selector_base_init (gpointer g_class)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||
|
||||
gst_element_class_set_details_simple (element_class, "Output selector",
|
||||
"Generic",
|
||||
"1-to-N output stream selectoring",
|
||||
"Stefan Kost <stefan.kost@nokia.com>");
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&gst_output_selector_sink_factory));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&gst_output_selector_src_factory));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_output_selector_class_init (GstOutputSelectorClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
gobject_class->dispose = gst_output_selector_dispose;
|
||||
|
||||
gobject_class->set_property =
|
||||
GST_DEBUG_FUNCPTR (gst_output_selector_set_property);
|
||||
gobject_class->get_property =
|
||||
GST_DEBUG_FUNCPTR (gst_output_selector_get_property);
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
|
||||
g_param_spec_object ("active-pad", "Active pad",
|
||||
"Currently active src pad", GST_TYPE_PAD,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_RESEND_LATEST,
|
||||
g_param_spec_boolean ("resend-latest", "Resend latest buffer",
|
||||
"Resend latest buffer after a switch to a new pad", FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gstelement_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_output_selector_request_new_pad);
|
||||
gstelement_class->release_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_output_selector_release_pad);
|
||||
|
||||
gstelement_class->change_state = gst_output_selector_change_state;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_output_selector_init (GstOutputSelector * sel,
|
||||
GstOutputSelectorClass * g_class)
|
||||
{
|
||||
sel->sinkpad =
|
||||
gst_pad_new_from_static_template (&gst_output_selector_sink_factory,
|
||||
"sink");
|
||||
gst_pad_set_chain_function (sel->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_output_selector_chain));
|
||||
gst_pad_set_event_function (sel->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_output_selector_handle_sink_event));
|
||||
gst_pad_set_bufferalloc_function (sel->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_output_selector_buffer_alloc));
|
||||
/*
|
||||
gst_pad_set_setcaps_function (sel->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
|
||||
gst_pad_set_getcaps_function (sel->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
|
||||
*/
|
||||
|
||||
gst_element_add_pad (GST_ELEMENT (sel), sel->sinkpad);
|
||||
|
||||
/* srcpad management */
|
||||
sel->active_srcpad = NULL;
|
||||
sel->nb_srcpads = 0;
|
||||
gst_segment_init (&sel->segment, GST_FORMAT_TIME);
|
||||
sel->pending_srcpad = NULL;
|
||||
|
||||
sel->resend_latest = FALSE;
|
||||
sel->latest_buffer = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_output_selector_reset (GstOutputSelector * osel)
|
||||
{
|
||||
if (osel->pending_srcpad != NULL) {
|
||||
gst_object_unref (osel->pending_srcpad);
|
||||
osel->pending_srcpad = NULL;
|
||||
}
|
||||
if (osel->latest_buffer != NULL) {
|
||||
gst_buffer_unref (osel->latest_buffer);
|
||||
osel->latest_buffer = NULL;
|
||||
}
|
||||
gst_segment_init (&osel->segment, GST_FORMAT_UNDEFINED);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_output_selector_dispose (GObject * object)
|
||||
{
|
||||
GstOutputSelector *osel = GST_OUTPUT_SELECTOR (object);
|
||||
|
||||
gst_output_selector_reset (osel);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_output_selector_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_ACTIVE_PAD:
|
||||
{
|
||||
GstPad *next_pad;
|
||||
|
||||
next_pad = g_value_get_object (value);
|
||||
|
||||
GST_INFO_OBJECT (sel, "Activating pad %s:%s",
|
||||
GST_DEBUG_PAD_NAME (next_pad));
|
||||
|
||||
GST_OBJECT_LOCK (object);
|
||||
if (next_pad != sel->active_srcpad) {
|
||||
/* switch to new srcpad in next chain run */
|
||||
if (sel->pending_srcpad != NULL) {
|
||||
GST_INFO ("replacing pending switch");
|
||||
gst_object_unref (sel->pending_srcpad);
|
||||
}
|
||||
if (next_pad)
|
||||
gst_object_ref (next_pad);
|
||||
sel->pending_srcpad = next_pad;
|
||||
} else {
|
||||
GST_INFO ("pad already active");
|
||||
if (sel->pending_srcpad != NULL) {
|
||||
gst_object_unref (sel->pending_srcpad);
|
||||
sel->pending_srcpad = NULL;
|
||||
}
|
||||
}
|
||||
GST_OBJECT_UNLOCK (object);
|
||||
break;
|
||||
}
|
||||
case PROP_RESEND_LATEST:{
|
||||
sel->resend_latest = g_value_get_boolean (value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_output_selector_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_ACTIVE_PAD:
|
||||
GST_OBJECT_LOCK (object);
|
||||
g_value_set_object (value,
|
||||
sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad);
|
||||
GST_OBJECT_UNLOCK (object);
|
||||
break;
|
||||
case PROP_RESEND_LATEST:{
|
||||
GST_OBJECT_LOCK (object);
|
||||
g_value_set_boolean (value, sel->resend_latest);
|
||||
GST_OBJECT_UNLOCK (object);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_output_selector_buffer_alloc (GstPad * pad, guint64 offset, guint size,
|
||||
GstCaps * caps, GstBuffer ** buf)
|
||||
{
|
||||
GstOutputSelector *sel;
|
||||
GstFlowReturn res;
|
||||
GstPad *allocpad;
|
||||
|
||||
sel = GST_OUTPUT_SELECTOR (GST_PAD_PARENT (pad));
|
||||
res = GST_FLOW_NOT_LINKED;
|
||||
|
||||
GST_OBJECT_LOCK (sel);
|
||||
allocpad = sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad;
|
||||
if (allocpad) {
|
||||
/* if we had a previous pad we used for allocating a buffer, continue using
|
||||
* it. */
|
||||
GST_DEBUG_OBJECT (sel, "using pad %s:%s for alloc",
|
||||
GST_DEBUG_PAD_NAME (allocpad));
|
||||
gst_object_ref (allocpad);
|
||||
GST_OBJECT_UNLOCK (sel);
|
||||
|
||||
res = gst_pad_alloc_buffer (allocpad, offset, size, caps, buf);
|
||||
gst_object_unref (allocpad);
|
||||
|
||||
GST_OBJECT_LOCK (sel);
|
||||
} else {
|
||||
/* fallback case, allocate a buffer of our own, add pad caps. */
|
||||
GST_DEBUG_OBJECT (pad, "fallback buffer alloc");
|
||||
*buf = NULL;
|
||||
res = GST_FLOW_OK;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (sel);
|
||||
|
||||
GST_DEBUG_OBJECT (sel, "buffer alloc finished: %s", gst_flow_get_name (res));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
gst_output_selector_request_new_pad (GstElement * element,
|
||||
GstPadTemplate * templ, const gchar * name)
|
||||
{
|
||||
gchar *padname;
|
||||
GstPad *srcpad;
|
||||
GstOutputSelector *osel;
|
||||
|
||||
osel = GST_OUTPUT_SELECTOR (element);
|
||||
|
||||
GST_DEBUG_OBJECT (osel, "requesting pad");
|
||||
|
||||
GST_OBJECT_LOCK (osel);
|
||||
padname = g_strdup_printf ("src%d", osel->nb_srcpads++);
|
||||
srcpad = gst_pad_new_from_template (templ, padname);
|
||||
GST_OBJECT_UNLOCK (osel);
|
||||
|
||||
gst_pad_set_active (srcpad, TRUE);
|
||||
gst_element_add_pad (GST_ELEMENT (osel), srcpad);
|
||||
|
||||
/* Set the first requested src pad as active by default */
|
||||
if (osel->active_srcpad == NULL) {
|
||||
osel->active_srcpad = srcpad;
|
||||
}
|
||||
g_free (padname);
|
||||
|
||||
return srcpad;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_output_selector_release_pad (GstElement * element, GstPad * pad)
|
||||
{
|
||||
GstOutputSelector *osel;
|
||||
|
||||
osel = GST_OUTPUT_SELECTOR (element);
|
||||
|
||||
GST_DEBUG_OBJECT (osel, "releasing pad");
|
||||
|
||||
gst_pad_set_active (pad, FALSE);
|
||||
|
||||
gst_element_remove_pad (GST_ELEMENT_CAST (osel), pad);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_output_selector_switch (GstOutputSelector * osel)
|
||||
{
|
||||
gboolean res = FALSE;
|
||||
GstEvent *ev = NULL;
|
||||
GstSegment *seg = NULL;
|
||||
gint64 start = 0, position = 0;
|
||||
|
||||
/* Switch */
|
||||
GST_OBJECT_LOCK (GST_OBJECT (osel));
|
||||
GST_INFO ("switching to pad %" GST_PTR_FORMAT, osel->pending_srcpad);
|
||||
if (gst_pad_is_linked (osel->pending_srcpad)) {
|
||||
osel->active_srcpad = osel->pending_srcpad;
|
||||
res = TRUE;
|
||||
}
|
||||
gst_object_unref (osel->pending_srcpad);
|
||||
osel->pending_srcpad = NULL;
|
||||
GST_OBJECT_UNLOCK (GST_OBJECT (osel));
|
||||
|
||||
/* Send NEWSEGMENT event and latest buffer if switching succeeded */
|
||||
if (res) {
|
||||
/* Send NEWSEGMENT to the pad we are going to switch to */
|
||||
seg = &osel->segment;
|
||||
/* If resending then mark newsegment start and position accordingly */
|
||||
if (osel->resend_latest && osel->latest_buffer &&
|
||||
GST_BUFFER_TIMESTAMP_IS_VALID (osel->latest_buffer)) {
|
||||
start = position = GST_BUFFER_TIMESTAMP (osel->latest_buffer);
|
||||
} else {
|
||||
start = position = seg->last_stop;
|
||||
}
|
||||
ev = gst_event_new_new_segment (TRUE, seg->rate,
|
||||
seg->format, start, seg->stop, position);
|
||||
if (!gst_pad_push_event (osel->active_srcpad, ev)) {
|
||||
GST_WARNING_OBJECT (osel,
|
||||
"newsegment handling failed in %" GST_PTR_FORMAT,
|
||||
osel->active_srcpad);
|
||||
}
|
||||
|
||||
/* Resend latest buffer to newly switched pad */
|
||||
if (osel->resend_latest && osel->latest_buffer) {
|
||||
GST_INFO ("resending latest buffer");
|
||||
gst_pad_push (osel->active_srcpad, gst_buffer_ref (osel->latest_buffer));
|
||||
}
|
||||
} else {
|
||||
GST_WARNING_OBJECT (osel, "switch failed, pad not linked");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_output_selector_chain (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GstFlowReturn res;
|
||||
GstOutputSelector *osel;
|
||||
GstClockTime last_stop, duration;
|
||||
|
||||
osel = GST_OUTPUT_SELECTOR (gst_pad_get_parent (pad));
|
||||
|
||||
/*
|
||||
* The _switch function might push a buffer if 'resend-latest' is true.
|
||||
*
|
||||
* Elements/Applications (e.g. camerabin) might use pad probes to
|
||||
* switch output-selector's active pad. If we simply switch and don't
|
||||
* recheck any pending pad switch the following codepath could end
|
||||
* up pushing a buffer on a non-active pad. This is bad.
|
||||
*
|
||||
* So we always should check the pending_srcpad before going further down
|
||||
* the chain and pushing the new buffer
|
||||
*/
|
||||
while (osel->pending_srcpad) {
|
||||
/* Do the switch */
|
||||
gst_output_selector_switch (osel);
|
||||
}
|
||||
|
||||
if (osel->latest_buffer) {
|
||||
gst_buffer_unref (osel->latest_buffer);
|
||||
osel->latest_buffer = NULL;
|
||||
}
|
||||
|
||||
if (osel->resend_latest) {
|
||||
/* Keep reference to latest buffer to resend it after switch */
|
||||
osel->latest_buffer = gst_buffer_ref (buf);
|
||||
}
|
||||
|
||||
/* Keep track of last stop and use it in NEWSEGMENT start after
|
||||
switching to a new src pad */
|
||||
last_stop = GST_BUFFER_TIMESTAMP (buf);
|
||||
if (GST_CLOCK_TIME_IS_VALID (last_stop)) {
|
||||
duration = GST_BUFFER_DURATION (buf);
|
||||
if (GST_CLOCK_TIME_IS_VALID (duration)) {
|
||||
last_stop += duration;
|
||||
}
|
||||
GST_LOG_OBJECT (osel, "setting last stop %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (last_stop));
|
||||
gst_segment_set_last_stop (&osel->segment, osel->segment.format, last_stop);
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (osel, "pushing buffer to %" GST_PTR_FORMAT,
|
||||
osel->active_srcpad);
|
||||
res = gst_pad_push (osel->active_srcpad, buf);
|
||||
gst_object_unref (osel);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_output_selector_change_state (GstElement * element,
|
||||
GstStateChange transition)
|
||||
{
|
||||
GstOutputSelector *sel;
|
||||
GstStateChangeReturn result;
|
||||
|
||||
sel = GST_OUTPUT_SELECTOR (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
gst_output_selector_reset (sel);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_output_selector_handle_sink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstOutputSelector *sel;
|
||||
GstPad *output_pad = NULL;
|
||||
|
||||
sel = GST_OUTPUT_SELECTOR (gst_pad_get_parent (pad));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_NEWSEGMENT:
|
||||
{
|
||||
gboolean update;
|
||||
GstFormat format;
|
||||
gdouble rate, arate;
|
||||
gint64 start, stop, time;
|
||||
|
||||
gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
|
||||
&start, &stop, &time);
|
||||
|
||||
GST_DEBUG_OBJECT (sel,
|
||||
"configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
|
||||
"format %d, " "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
|
||||
G_GINT64_FORMAT, update, rate, arate, format, start, stop, time);
|
||||
|
||||
gst_segment_set_newsegment_full (&sel->segment, update,
|
||||
rate, arate, format, start, stop, time);
|
||||
|
||||
/* Send newsegment to all src pads */
|
||||
gst_pad_event_default (pad, event);
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_EOS:
|
||||
/* Send eos to all src pads */
|
||||
gst_pad_event_default (pad, event);
|
||||
break;
|
||||
default:
|
||||
/* Send other events to pending or active src pad */
|
||||
output_pad =
|
||||
sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad;
|
||||
res = gst_pad_push_event (output_pad, event);
|
||||
break;
|
||||
}
|
||||
|
||||
gst_object_unref (sel);
|
||||
|
||||
return res;
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_OUTPUT_SELECTOR_H__
|
||||
#define __GST_OUTPUT_SELECTOR_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_OUTPUT_SELECTOR \
|
||||
(gst_output_selector_get_type())
|
||||
#define GST_OUTPUT_SELECTOR(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OUTPUT_SELECTOR, GstOutputSelector))
|
||||
#define GST_OUTPUT_SELECTOR_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_OUTPUT_SELECTOR, GstOutputSelectorClass))
|
||||
#define GST_IS_OUTPUT_SELECTOR(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OUTPUT_SELECTOR))
|
||||
#define GST_IS_OUTPUT_SELECTOR_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_OUTPUT_SELECTOR))
|
||||
|
||||
typedef struct _GstOutputSelector GstOutputSelector;
|
||||
typedef struct _GstOutputSelectorClass GstOutputSelectorClass;
|
||||
|
||||
struct _GstOutputSelector {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
|
||||
GstPad *active_srcpad;
|
||||
GstPad *pending_srcpad;
|
||||
guint nb_srcpads;
|
||||
|
||||
GstSegment segment;
|
||||
|
||||
/* resend latest buffer after switch */
|
||||
gboolean resend_latest;
|
||||
GstBuffer *latest_buffer;
|
||||
|
||||
};
|
||||
|
||||
struct _GstOutputSelectorClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_output_selector_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_OUTPUT_SELECTOR_H__ */
|
|
@ -1,2 +0,0 @@
|
|||
INT64:VOID
|
||||
VOID:OBJECT,INT64,INT64
|
|
@ -1,44 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gstinputselector.h"
|
||||
#include "gstoutputselector.h"
|
||||
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
|
||||
return gst_element_register (plugin, "input-selector",
|
||||
GST_RANK_NONE, GST_TYPE_INPUT_SELECTOR) &&
|
||||
gst_element_register (plugin, "output-selector",
|
||||
GST_RANK_NONE, GST_TYPE_OUTPUT_SELECTOR);
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"selector",
|
||||
"input/output stream selector elements",
|
||||
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|
|
@ -1,148 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="selector"
|
||||
ProjectGUID="{979C216F-0ACF-4956-AE00-055A42D678CF}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="../../win32/Debug"
|
||||
IntermediateDirectory="../../win32/Debug"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;"../../gst-libs";../../../popt/include;../../../libxml2/include/libxml2"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;selector_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
|
||||
OutputFile="$(OutDir)/gstselector.dll"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="../../../gstreamer/win32/Debug;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
|
||||
ModuleDefinitionFile=""
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/selectro.pdb"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
ImportLibrary="$(OutDir)/gstselectro.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="../../win32/Release"
|
||||
IntermediateDirectory="../../win32/Release"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;"../../gst-libs";../../../popt/include;../../../libxml2/include/libxml2"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;GST_DISABLE_GST_DEBUG;_WINDOWS;_USRDLL;selector_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
|
||||
OutputFile="$(OutDir)/gstselector.dll"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="../../../gstreamer/win32/Release;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
|
||||
ModuleDefinitionFile=""
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
ImportLibrary="$(OutDir)/gstselector.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath=".\gstselector.c">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath=".\gstselector.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -162,7 +162,6 @@ check_PROGRAMS = \
|
|||
$(check_jifmux) \
|
||||
elements/jpegparse \
|
||||
elements/qtmux \
|
||||
elements/selector \
|
||||
elements/mxfdemux \
|
||||
elements/mxfmux \
|
||||
elements/id3mux \
|
||||
|
|
1
tests/check/elements/.gitignore
vendored
1
tests/check/elements/.gitignore
vendored
|
@ -34,7 +34,6 @@ rganalysis
|
|||
rglimiter
|
||||
rgvolume
|
||||
rtpmux
|
||||
selector
|
||||
spectrum
|
||||
timidity
|
||||
y4menc
|
||||
|
|
|
@ -1,385 +0,0 @@
|
|||
/* GStreamer
|
||||
*
|
||||
* Unit test for selector plugin
|
||||
* Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <gst/check/gstcheck.h>
|
||||
|
||||
#define NUM_SELECTOR_PADS 4
|
||||
#define NUM_INPUT_BUFFERS 4 // buffers to send per each selector pad
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
/* Data probe cb to drop everything but count buffers and events */
|
||||
static gboolean
|
||||
probe_cb (GstPad * pad, GstMiniObject * obj, gpointer user_data)
|
||||
{
|
||||
gint count = 0;
|
||||
const gchar *count_type = NULL;
|
||||
|
||||
GST_LOG_OBJECT (pad, "got data");
|
||||
|
||||
if (GST_IS_BUFFER (obj)) {
|
||||
count_type = "buffer_count";
|
||||
} else if (GST_IS_EVENT (obj)) {
|
||||
count_type = "event_count";
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
/* increment and store count */
|
||||
count = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pad), count_type));
|
||||
count++;
|
||||
g_object_set_data (G_OBJECT (pad), count_type, GINT_TO_POINTER (count));
|
||||
|
||||
/* drop everything */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Create and link output pad: selector:src%d ! output_pad */
|
||||
static GstPad *
|
||||
setup_output_pad (GstElement * element)
|
||||
{
|
||||
GstPad *srcpad = NULL, *output_pad = NULL;
|
||||
gulong probe_id = 0;
|
||||
|
||||
/* create output_pad */
|
||||
output_pad = gst_pad_new_from_static_template (&sinktemplate, "sink");
|
||||
fail_if (output_pad == NULL, "Could not create a output_pad");
|
||||
|
||||
/* add probe */
|
||||
probe_id = gst_pad_add_data_probe (output_pad, G_CALLBACK (probe_cb), NULL);
|
||||
g_object_set_data (G_OBJECT (output_pad), "probe_id",
|
||||
GINT_TO_POINTER (probe_id));
|
||||
|
||||
/* request src pad */
|
||||
srcpad = gst_element_get_request_pad (element, "src%d");
|
||||
fail_if (srcpad == NULL, "Could not get source pad from %s",
|
||||
GST_ELEMENT_NAME (element));
|
||||
|
||||
/* link pads and activate */
|
||||
fail_unless (gst_pad_link (srcpad, output_pad) == GST_PAD_LINK_OK,
|
||||
"Could not link %s source and output pad", GST_ELEMENT_NAME (element));
|
||||
|
||||
gst_pad_set_active (output_pad, TRUE);
|
||||
|
||||
GST_DEBUG_OBJECT (output_pad, "set up %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT,
|
||||
srcpad, output_pad);
|
||||
|
||||
gst_object_unref (srcpad);
|
||||
ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1);
|
||||
|
||||
return output_pad;
|
||||
}
|
||||
|
||||
/* Clean up output/input pad and respective selector request pad */
|
||||
static void
|
||||
cleanup_pad (GstPad * pad, GstElement * element)
|
||||
{
|
||||
GstPad *selpad = NULL;
|
||||
guint probe_id = 0;
|
||||
|
||||
fail_if (pad == NULL, "pad doesn't exist");
|
||||
|
||||
/* remove probe if necessary */
|
||||
probe_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pad), "probe_id"));
|
||||
if (probe_id)
|
||||
gst_pad_remove_data_probe (pad, probe_id);
|
||||
|
||||
/* unlink */
|
||||
selpad = gst_pad_get_peer (pad);
|
||||
if (GST_PAD_DIRECTION (selpad) == GST_PAD_SRC) {
|
||||
gst_pad_unlink (selpad, pad);
|
||||
} else {
|
||||
gst_pad_unlink (pad, selpad);
|
||||
}
|
||||
|
||||
/* caps could have been set, make sure they get unset */
|
||||
gst_pad_set_caps (pad, NULL);
|
||||
|
||||
GST_DEBUG_OBJECT (pad, "clean up %" GST_PTR_FORMAT " and %" GST_PTR_FORMAT,
|
||||
selpad, pad);
|
||||
|
||||
/* cleanup the pad */
|
||||
gst_pad_set_active (pad, FALSE);
|
||||
ASSERT_OBJECT_REFCOUNT (pad, "pad", 1);
|
||||
gst_object_unref (pad);
|
||||
|
||||
/* cleanup selector pad, reffed by this function (_get_peer) and creator */
|
||||
gst_element_release_request_pad (element, selpad);
|
||||
gst_object_unref (selpad);
|
||||
}
|
||||
|
||||
/* Duplicate and push given buffer many times to all input_pads */
|
||||
static void
|
||||
push_input_buffers (GList * input_pads, GstBuffer * buf, gint num_buffers)
|
||||
{
|
||||
GstBuffer *buf_in = NULL;
|
||||
GList *l = input_pads;
|
||||
GstPad *input_pad;
|
||||
gint i = 0;
|
||||
|
||||
while (l != NULL) {
|
||||
input_pad = l->data;
|
||||
GST_DEBUG_OBJECT (input_pad, "pushing %d buffers to %" GST_PTR_FORMAT,
|
||||
num_buffers, input_pad);
|
||||
for (i = 0; i < num_buffers; i++) {
|
||||
buf_in = gst_buffer_copy (buf);
|
||||
fail_unless (gst_pad_push (input_pad, buf_in) == GST_FLOW_OK,
|
||||
"pushing buffer failed");
|
||||
}
|
||||
l = g_list_next (l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that received buffers count match to expected buffers */
|
||||
static void
|
||||
count_output_buffers (GList * output_pads, gint expected_buffers)
|
||||
{
|
||||
gint count = 0;
|
||||
GList *l = output_pads;
|
||||
GstPad *output_pad = NULL;
|
||||
|
||||
while (l != NULL) {
|
||||
output_pad = l->data;
|
||||
count =
|
||||
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (output_pad),
|
||||
"buffer_count"));
|
||||
GST_DEBUG_OBJECT (output_pad, "received %d buffers", count);
|
||||
fail_unless (count == expected_buffers,
|
||||
"received/expected buffer count doesn't match %d/%d", count,
|
||||
expected_buffers);
|
||||
count =
|
||||
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (output_pad),
|
||||
"event_count"));
|
||||
GST_DEBUG_OBJECT (output_pad, "received %d events", count);
|
||||
l = g_list_next (l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set selector active pad */
|
||||
static void
|
||||
selector_set_active_pad (GstElement * elem, GstPad * selpad)
|
||||
{
|
||||
gchar *padname = NULL;
|
||||
|
||||
if (selpad) {
|
||||
padname = gst_pad_get_name (selpad);
|
||||
}
|
||||
|
||||
g_object_set (G_OBJECT (elem), "active-pad", selpad, NULL);
|
||||
GST_DEBUG_OBJECT (elem, "activated selector pad: %s", GST_STR_NULL (padname));
|
||||
g_free (padname);
|
||||
}
|
||||
|
||||
/* Push buffers and switch for each selector pad */
|
||||
static void
|
||||
push_switched_buffers (GList * input_pads,
|
||||
GstElement * elem, GList * peer_pads, gint num_buffers)
|
||||
{
|
||||
GstBuffer *buf = NULL;
|
||||
GstCaps *caps = NULL;
|
||||
GList *l = peer_pads;
|
||||
GstPad *selpad = NULL;
|
||||
|
||||
/* setup dummy buffer */
|
||||
caps = gst_caps_from_string ("application/x-unknown");
|
||||
buf = gst_buffer_new_and_alloc (1);
|
||||
gst_buffer_set_caps (buf, caps);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
while (l != NULL) {
|
||||
/* set selector pad */
|
||||
selpad = gst_pad_get_peer (GST_PAD (l->data));
|
||||
selector_set_active_pad (elem, selpad);
|
||||
if (selpad) {
|
||||
gst_object_unref (selpad);
|
||||
}
|
||||
/* push buffers */
|
||||
push_input_buffers (input_pads, buf, num_buffers);
|
||||
/* switch to next selector pad */
|
||||
l = g_list_next (l);
|
||||
}
|
||||
|
||||
/* cleanup buffer */
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
|
||||
/* Create output-selector with given number of src pads and switch
|
||||
given number of input buffers to each src pad.
|
||||
*/
|
||||
static void
|
||||
run_output_selector_buffer_count (gint num_output_pads,
|
||||
gint num_buffers_per_output)
|
||||
{
|
||||
/* setup input_pad ! selector ! output_pads */
|
||||
gint i = 0;
|
||||
GList *output_pads = NULL, *input_pads = NULL;
|
||||
GstElement *sel = gst_check_setup_element ("output-selector");
|
||||
GstPad *input_pad = gst_check_setup_src_pad (sel, &srctemplate, NULL);
|
||||
|
||||
input_pads = g_list_append (input_pads, input_pad);
|
||||
gst_pad_set_active (input_pad, TRUE);
|
||||
for (i = 0; i < num_output_pads; i++) {
|
||||
output_pads = g_list_append (output_pads, setup_output_pad (sel));
|
||||
}
|
||||
|
||||
/* run the test */
|
||||
fail_unless (gst_element_set_state (sel,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
||||
"could not set to playing");
|
||||
push_switched_buffers (input_pads, sel, output_pads, num_buffers_per_output);
|
||||
count_output_buffers (output_pads, num_buffers_per_output);
|
||||
fail_unless (gst_element_set_state (sel,
|
||||
GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
|
||||
|
||||
/* cleanup input_pad, selector and output_pads */
|
||||
gst_pad_set_active (input_pad, FALSE);
|
||||
gst_check_teardown_src_pad (sel);
|
||||
g_list_foreach (output_pads, (GFunc) cleanup_pad, sel);
|
||||
g_list_free (output_pads);
|
||||
g_list_free (input_pads);
|
||||
gst_check_teardown_element (sel);
|
||||
}
|
||||
|
||||
/* Create and link input pad: input_pad ! selector:sink%d */
|
||||
static GstPad *
|
||||
setup_input_pad (GstElement * element)
|
||||
{
|
||||
GstPad *sinkpad = NULL, *input_pad = NULL;
|
||||
|
||||
/* create input_pad */
|
||||
input_pad = gst_pad_new_from_static_template (&srctemplate, "src");
|
||||
fail_if (input_pad == NULL, "Could not create a input_pad");
|
||||
|
||||
/* request sink pad */
|
||||
sinkpad = gst_element_get_request_pad (element, "sink%d");
|
||||
fail_if (sinkpad == NULL, "Could not get sink pad from %s",
|
||||
GST_ELEMENT_NAME (element));
|
||||
|
||||
/* link pads and activate */
|
||||
fail_unless (gst_pad_link (input_pad, sinkpad) == GST_PAD_LINK_OK,
|
||||
"Could not link input_pad and %s sink", GST_ELEMENT_NAME (element));
|
||||
|
||||
gst_pad_set_active (input_pad, TRUE);
|
||||
|
||||
GST_DEBUG_OBJECT (input_pad, "set up %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT,
|
||||
input_pad, sinkpad);
|
||||
|
||||
gst_object_unref (sinkpad);
|
||||
ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
|
||||
|
||||
return input_pad;
|
||||
}
|
||||
|
||||
/* Create input-selector with given number of sink pads and switch
|
||||
given number of input buffers to each sink pad.
|
||||
*/
|
||||
static void
|
||||
run_input_selector_buffer_count (gint num_input_pads,
|
||||
gint num_buffers_per_input)
|
||||
{
|
||||
/* set up input_pads ! selector ! output_pad */
|
||||
gint i = 0, probe_id = 0;
|
||||
GList *input_pads = NULL, *output_pads = NULL;
|
||||
GstElement *sel = gst_check_setup_element ("input-selector");
|
||||
GstPad *output_pad = gst_check_setup_sink_pad (sel, &sinktemplate, NULL);
|
||||
|
||||
output_pads = g_list_append (output_pads, output_pad);
|
||||
gst_pad_set_active (output_pad, TRUE);
|
||||
for (i = 0; i < num_input_pads; i++) {
|
||||
input_pads = g_list_append (input_pads, setup_input_pad (sel));
|
||||
}
|
||||
/* add probe */
|
||||
probe_id = gst_pad_add_data_probe (output_pad, G_CALLBACK (probe_cb), NULL);
|
||||
g_object_set_data (G_OBJECT (output_pad), "probe_id",
|
||||
GINT_TO_POINTER (probe_id));
|
||||
|
||||
/* run the test */
|
||||
fail_unless (gst_element_set_state (sel,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
||||
"could not set to playing");
|
||||
push_switched_buffers (input_pads, sel, input_pads, num_buffers_per_input);
|
||||
count_output_buffers (output_pads, (num_input_pads * num_buffers_per_input));
|
||||
fail_unless (gst_element_set_state (sel,
|
||||
GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
|
||||
|
||||
/* clean up */
|
||||
gst_pad_remove_data_probe (output_pad, probe_id);
|
||||
gst_pad_set_active (output_pad, FALSE);
|
||||
gst_check_teardown_sink_pad (sel);
|
||||
GST_DEBUG ("setting selector pad to NULL");
|
||||
selector_set_active_pad (sel, NULL); // unref input-selector active pad
|
||||
g_list_foreach (input_pads, (GFunc) cleanup_pad, sel);
|
||||
g_list_free (input_pads);
|
||||
g_list_free (output_pads);
|
||||
gst_check_teardown_element (sel);
|
||||
}
|
||||
|
||||
/* Push buffers to input pad and check the
|
||||
amount of buffers arrived to output pads */
|
||||
GST_START_TEST (test_output_selector_buffer_count);
|
||||
{
|
||||
gint i, j;
|
||||
|
||||
for (i = 0; i < NUM_SELECTOR_PADS; i++) {
|
||||
for (j = 0; j < NUM_INPUT_BUFFERS; j++) {
|
||||
run_output_selector_buffer_count (i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
/* Push buffers to input pads and check the
|
||||
amount of buffers arrived to output pad */
|
||||
GST_START_TEST (test_input_selector_buffer_count);
|
||||
{
|
||||
gint i, j;
|
||||
|
||||
for (i = 0; i < NUM_SELECTOR_PADS; i++) {
|
||||
for (j = 0; j < NUM_INPUT_BUFFERS; j++) {
|
||||
run_input_selector_buffer_count (i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
selector_suite (void)
|
||||
{
|
||||
Suite *s = suite_create ("selector");
|
||||
TCase *tc_chain = tcase_create ("general");
|
||||
|
||||
suite_add_tcase (s, tc_chain);
|
||||
tcase_add_test (tc_chain, test_output_selector_buffer_count);
|
||||
tcase_add_test (tc_chain, test_input_selector_buffer_count);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
GST_CHECK_MAIN (selector);
|
|
@ -21,5 +21,7 @@ else
|
|||
CAMERABIN2=
|
||||
endif
|
||||
|
||||
SUBDIRS= $(DIRECTFB_DIR) $(GTK_EXAMPLES) $(JACK_EXAMPLES) switch
|
||||
DIST_SUBDIRS= camerabin $(CAMERABIN2) directfb jack mxf scaletempo switch
|
||||
SUBDIRS= $(DIRECTFB_DIR) $(GTK_EXAMPLES) $(JACK_EXAMPLES)
|
||||
DIST_SUBDIRS= camerabin $(CAMERABIN2) directfb jack mxf scaletempo
|
||||
|
||||
include $(top_srcdir)/common/parallel-subdirs.mak
|
||||
|
|
1
tests/examples/switch/.gitignore
vendored
1
tests/examples/switch/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
switcher
|
|
@ -1,7 +0,0 @@
|
|||
|
||||
noinst_PROGRAMS = switcher
|
||||
|
||||
switcher_SOURCES = switcher.c
|
||||
switcher_CFLAGS = $(GST_CFLAGS)
|
||||
switcher_LDFLAGS = $(GST_LIBS)
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2003 Julien Moutte <julien@moutte.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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
static GMainLoop *loop = NULL;
|
||||
|
||||
static gboolean
|
||||
my_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
|
||||
{
|
||||
g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
|
||||
|
||||
switch (GST_MESSAGE_TYPE (message)) {
|
||||
case GST_MESSAGE_ERROR:{
|
||||
GError *err;
|
||||
gchar *debug;
|
||||
|
||||
gst_message_parse_error (message, &err, &debug);
|
||||
g_print ("Error: %s\n", err->message);
|
||||
g_error_free (err);
|
||||
g_free (debug);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
break;
|
||||
}
|
||||
case GST_MESSAGE_EOS:
|
||||
/* end-of-stream */
|
||||
g_main_loop_quit (loop);
|
||||
break;
|
||||
default:
|
||||
/* unhandled message */
|
||||
break;
|
||||
}
|
||||
|
||||
/* we want to be notified again the next time there is a message
|
||||
* on the bus, so returning TRUE (FALSE means we want to stop watching
|
||||
* for messages on the bus and our callback should not be called again)
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
switch_timer (GstElement * video_switch)
|
||||
{
|
||||
gint nb_sources;
|
||||
GstPad *active_pad, *new_pad;
|
||||
gchar *active_name;
|
||||
|
||||
g_message ("switching");
|
||||
g_object_get (G_OBJECT (video_switch), "n-pads", &nb_sources, NULL);
|
||||
g_object_get (G_OBJECT (video_switch), "active-pad", &active_pad, NULL);
|
||||
|
||||
active_name = gst_pad_get_name (active_pad);
|
||||
if (strcmp (active_name, "sink0") == 0) {
|
||||
new_pad = gst_element_get_static_pad (video_switch, "sink1");
|
||||
} else {
|
||||
new_pad = gst_element_get_static_pad (video_switch, "sink0");
|
||||
}
|
||||
g_object_set (G_OBJECT (video_switch), "active-pad", new_pad, NULL);
|
||||
g_free (active_name);
|
||||
gst_object_unref (new_pad);
|
||||
|
||||
g_message ("current number of sources : %d, active source %s",
|
||||
nb_sources, gst_pad_get_name (active_pad));
|
||||
|
||||
return (GST_STATE (GST_ELEMENT (video_switch)) == GST_STATE_PLAYING);
|
||||
}
|
||||
|
||||
static void
|
||||
last_message_received (GObject * segment)
|
||||
{
|
||||
gchar *last_message;
|
||||
|
||||
g_object_get (segment, "last_message", &last_message, NULL);
|
||||
g_print ("last-message: %s\n", last_message);
|
||||
g_free (last_message);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GstElement *pipeline, *src1, *src2, *video_switch, *video_sink, *segment;
|
||||
GstElement *sink1_sync, *sink2_sync, *capsfilter;
|
||||
GstBus *bus;
|
||||
|
||||
/* Initing GStreamer library */
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
pipeline = gst_pipeline_new ("pipeline");
|
||||
src1 = gst_element_factory_make ("videotestsrc", "src1");
|
||||
g_object_set (G_OBJECT (src1), "pattern", 0, NULL);
|
||||
src2 = gst_element_factory_make ("videotestsrc", "src2");
|
||||
g_object_set (G_OBJECT (src2), "pattern", 1, NULL);
|
||||
capsfilter = gst_element_factory_make ("capsfilter", "caps0");
|
||||
g_object_set (G_OBJECT (capsfilter), "caps",
|
||||
gst_caps_from_string ("video/x-raw-rgb,width=640,height=480"), NULL);
|
||||
video_switch = gst_element_factory_make ("input-selector", "video_switch");
|
||||
segment = gst_element_factory_make ("identity", "identity-segment");
|
||||
g_object_set (G_OBJECT (segment), "silent", TRUE, NULL);
|
||||
g_signal_connect (G_OBJECT (segment), "notify::last-message",
|
||||
G_CALLBACK (last_message_received), segment);
|
||||
g_object_set (G_OBJECT (segment), "single-segment", TRUE, NULL);
|
||||
video_sink = gst_element_factory_make ("ximagesink", "video_sink");
|
||||
g_object_set (G_OBJECT (video_sink), "sync", FALSE, NULL);
|
||||
sink1_sync = gst_element_factory_make ("identity", "sink0_sync");
|
||||
g_object_set (G_OBJECT (sink1_sync), "sync", TRUE, NULL);
|
||||
sink2_sync = gst_element_factory_make ("identity", "sink1_sync");
|
||||
g_object_set (G_OBJECT (sink2_sync), "sync", TRUE, NULL);
|
||||
gst_bin_add_many (GST_BIN (pipeline), src1, src2, segment, video_switch,
|
||||
video_sink, sink1_sync, sink2_sync, capsfilter, NULL);
|
||||
gst_element_link (src1, sink1_sync);
|
||||
gst_element_link (sink1_sync, video_switch);
|
||||
gst_element_link (src2, capsfilter);
|
||||
gst_element_link (capsfilter, sink2_sync);
|
||||
gst_element_link (sink2_sync, video_switch);
|
||||
gst_element_link (video_switch, segment);
|
||||
gst_element_link (segment, /*scaler);
|
||||
gst_element_link (scaler, */ video_sink);
|
||||
|
||||
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
||||
gst_bus_add_watch (bus, my_bus_callback, NULL);
|
||||
gst_object_unref (bus);
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
|
||||
g_timeout_add (200, (GSourceFunc) switch_timer, video_switch);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_READY);
|
||||
|
||||
/* unref */
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
exit (0);
|
||||
}
|
1
tests/icles/.gitignore
vendored
1
tests/icles/.gitignore
vendored
|
@ -1,6 +1,5 @@
|
|||
equalizer-test
|
||||
metadata_editor
|
||||
output-selector-test
|
||||
pitch-test
|
||||
cog-test
|
||||
cog-test.c
|
||||
|
|
|
@ -30,12 +30,6 @@ equalizer_test_CFLAGS = $(GST_CFLAGS)
|
|||
equalizer_test_LDADD = $(GST_LIBS)
|
||||
equalizer_test_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
output_selector_test_SOURCES = output-selector-test.c
|
||||
output_selector_test_CFLAGS = $(GST_CFLAGS)
|
||||
output_selector_test_LDADD = $(GST_LIBS)
|
||||
output_selector_test_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
|
||||
noinst_PROGRAMS = $(GST_SOUNDTOUCH_TESTS) $(GST_METADATA_TESTS) \
|
||||
equalizer-test output-selector-test
|
||||
equalizer-test
|
||||
|
||||
|
|
|
@ -1,173 +0,0 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
#define SWITCH_TIMEOUT 1000
|
||||
#define NUM_VIDEO_BUFFERS 500
|
||||
|
||||
static GMainLoop *loop;
|
||||
|
||||
/* Output selector src pads */
|
||||
static GstPad *osel_src1 = NULL;
|
||||
static GstPad *osel_src2 = NULL;
|
||||
|
||||
static gboolean
|
||||
my_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
|
||||
{
|
||||
g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
|
||||
|
||||
switch (GST_MESSAGE_TYPE (message)) {
|
||||
case GST_MESSAGE_ERROR:{
|
||||
GError *err;
|
||||
gchar *debug;
|
||||
|
||||
gst_message_parse_error (message, &err, &debug);
|
||||
g_print ("Error: %s\n", err->message);
|
||||
g_error_free (err);
|
||||
g_free (debug);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
break;
|
||||
}
|
||||
case GST_MESSAGE_EOS:
|
||||
/* end-of-stream */
|
||||
g_main_loop_quit (loop);
|
||||
break;
|
||||
default:
|
||||
/* unhandled message */
|
||||
break;
|
||||
}
|
||||
/* we want to be notified again the next time there is a message
|
||||
* on the bus, so returning TRUE (FALSE means we want to stop watching
|
||||
* for messages on the bus and our callback should not be called again)
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
switch_cb (gpointer user_data)
|
||||
{
|
||||
GstElement *sel = GST_ELEMENT (user_data);
|
||||
GstPad *old_pad, *new_pad = NULL;
|
||||
|
||||
g_object_get (G_OBJECT (sel), "active-pad", &old_pad, NULL);
|
||||
|
||||
if (old_pad == osel_src1)
|
||||
new_pad = osel_src2;
|
||||
else
|
||||
new_pad = osel_src1;
|
||||
|
||||
g_object_set (G_OBJECT (sel), "active-pad", new_pad, NULL);
|
||||
|
||||
g_print ("switched from %s:%s to %s:%s\n", GST_DEBUG_PAD_NAME (old_pad),
|
||||
GST_DEBUG_PAD_NAME (new_pad));
|
||||
|
||||
gst_object_unref (old_pad);
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
on_bin_element_added (GstBin * bin, GstElement * element, gpointer user_data)
|
||||
{
|
||||
g_object_set (G_OBJECT (element), "sync", FALSE, "async", FALSE, NULL);
|
||||
}
|
||||
|
||||
gint
|
||||
main (gint argc, gchar * argv[])
|
||||
{
|
||||
GstElement *pipeline, *src, *toverlay, *osel, *sink1, *sink2, *c1, *c2, *c0;
|
||||
GstPad *sinkpad;
|
||||
GstBus *bus;
|
||||
|
||||
/* init GStreamer */
|
||||
gst_init (&argc, &argv);
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
/* create elements */
|
||||
pipeline = gst_element_factory_make ("pipeline", "pipeline");
|
||||
src = gst_element_factory_make ("videotestsrc", "src");
|
||||
c0 = gst_element_factory_make ("ffmpegcolorspace", NULL);
|
||||
toverlay = gst_element_factory_make ("timeoverlay", "timeoverlay");
|
||||
osel = gst_element_factory_make ("output-selector", "osel");
|
||||
c1 = gst_element_factory_make ("ffmpegcolorspace", NULL);
|
||||
c2 = gst_element_factory_make ("ffmpegcolorspace", NULL);
|
||||
sink1 = gst_element_factory_make ("autovideosink", "sink1");
|
||||
sink2 = gst_element_factory_make ("autovideosink", "sink2");
|
||||
|
||||
if (!pipeline || !src || !c0 || !toverlay || !osel || !c1 || !c2 || !sink1 ||
|
||||
!sink2) {
|
||||
g_print ("missing element\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* add them to bin */
|
||||
gst_bin_add_many (GST_BIN (pipeline), src, c0, toverlay, osel, c1, sink1, c2,
|
||||
sink2, NULL);
|
||||
|
||||
/* set properties */
|
||||
g_object_set (G_OBJECT (src), "is-live", TRUE, NULL);
|
||||
g_object_set (G_OBJECT (src), "do-timestamp", TRUE, NULL);
|
||||
g_object_set (G_OBJECT (src), "num-buffers", NUM_VIDEO_BUFFERS, NULL);
|
||||
g_object_set (G_OBJECT (osel), "resend-latest", TRUE, NULL);
|
||||
|
||||
/* handle deferred properties */
|
||||
g_signal_connect (G_OBJECT (sink1), "element-added",
|
||||
G_CALLBACK (on_bin_element_added), NULL);
|
||||
g_signal_connect (G_OBJECT (sink2), "element-added",
|
||||
G_CALLBACK (on_bin_element_added), NULL);
|
||||
|
||||
/* link src ! timeoverlay ! osel */
|
||||
if (!gst_element_link_many (src, c0, toverlay, osel, NULL)) {
|
||||
g_print ("linking failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* link output 1 */
|
||||
sinkpad = gst_element_get_static_pad (c1, "sink");
|
||||
osel_src1 = gst_element_get_request_pad (osel, "src%d");
|
||||
if (gst_pad_link (osel_src1, sinkpad) != GST_PAD_LINK_OK) {
|
||||
g_print ("linking output 1 converter failed\n");
|
||||
return -1;
|
||||
}
|
||||
gst_object_unref (sinkpad);
|
||||
|
||||
if (!gst_element_link (c1, sink1)) {
|
||||
g_print ("linking output 1 failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* link output 2 */
|
||||
sinkpad = gst_element_get_static_pad (c2, "sink");
|
||||
osel_src2 = gst_element_get_request_pad (osel, "src%d");
|
||||
if (gst_pad_link (osel_src2, sinkpad) != GST_PAD_LINK_OK) {
|
||||
g_print ("linking output 2 converter failed\n");
|
||||
return -1;
|
||||
}
|
||||
gst_object_unref (sinkpad);
|
||||
|
||||
if (!gst_element_link (c2, sink2)) {
|
||||
g_print ("linking output 2 failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* add switch callback */
|
||||
g_timeout_add (SWITCH_TIMEOUT, switch_cb, osel);
|
||||
|
||||
/* change to playing */
|
||||
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
||||
gst_bus_add_watch (bus, my_bus_callback, loop);
|
||||
gst_object_unref (bus);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
/* now run */
|
||||
g_main_loop_run (loop);
|
||||
|
||||
/* also clean up */
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
gst_element_release_request_pad (osel, osel_src1);
|
||||
gst_element_release_request_pad (osel, osel_src2);
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue