selector: move input-selector and output-selector to core

https://bugzilla.gnome.org/show_bug.cgi?id=614306
This commit is contained in:
Tim-Philipp Müller 2010-12-31 01:38:02 +00:00
parent 44946440a2
commit c6c3d9781b
28 changed files with 11 additions and 3359 deletions

View file

@ -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

View file

@ -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

View file

@ -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 \

View file

@ -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" />

View file

@ -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>

View file

@ -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>

View file

@ -223,7 +223,6 @@ GObject
GstISMLMux
GstId3BaseMux
GstId3Mux
GstInputSelector
GstInterlace
GstInvtelecine
GstIvfParse
@ -254,7 +253,6 @@ GObject
GstMveMux
GstNsfDec
GstNuvDemux
GstOutputSelector
GstPcapParse
GstPitch
GstPnmdec

View file

@ -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 &lt;julien@moutte.net&gt;, Jan Schmidt &lt;thaytan@mad.scientist.com&gt;, Wim Taymans &lt;wim.taymans@gmail.com&gt;</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 &lt;stefan.kost@nokia.com&gt;</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>

View file

@ -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

View file

@ -1,2 +0,0 @@
gstselector-marshal.c
gstselector-marshal.h

View file

@ -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

View file

@ -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__ */

View file

@ -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;
}

View file

@ -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__ */

View file

@ -1,2 +0,0 @@
INT64:VOID
VOID:OBJECT,INT64,INT64

View file

@ -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)

View file

@ -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;&quot;../../gst-libs&quot;;../../../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;&quot;../../gst-libs&quot;;../../../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>

View file

@ -162,7 +162,6 @@ check_PROGRAMS = \
$(check_jifmux) \
elements/jpegparse \
elements/qtmux \
elements/selector \
elements/mxfdemux \
elements/mxfmux \
elements/id3mux \

View file

@ -34,7 +34,6 @@ rganalysis
rglimiter
rgvolume
rtpmux
selector
spectrum
timidity
y4menc

View file

@ -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);

View file

@ -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

View file

@ -1 +0,0 @@
switcher

View file

@ -1,7 +0,0 @@
noinst_PROGRAMS = switcher
switcher_SOURCES = switcher.c
switcher_CFLAGS = $(GST_CFLAGS)
switcher_LDFLAGS = $(GST_LIBS)

View file

@ -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);
}

View file

@ -1,6 +1,5 @@
equalizer-test
metadata_editor
output-selector-test
pitch-test
cog-test
cog-test.c

View file

@ -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

View file

@ -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;
}