Commit 4a583683 authored by Erik Walthinsen's avatar Erik Walthinsen

Merged from INCSCHED on 200505251!!!

Original commit message from CVS:
Merged from INCSCHED on 200505251!!!
parent 54271eca
......@@ -11,6 +11,8 @@ config.sub
configure
gstreamer-[0-9]*
gstreamer-config
gstreamer.pc
gstreamer-uninstalled.pc
gstreamer.spec
libtool
ltconfig
......
......@@ -3,6 +3,8 @@ Matt Howell <mhowell@users.sourceforge.net>
Brent Bradburn <bbradburn@users.sourceforge.net>
Wim Taymans <wim.taymans@tvd.be>
Richard Boulton <richard@tartarus.org>
Zaheer Merali <zaheer@grid9.net>
- thread synchronization rework
David I. Lehn <dlehn@users.sourceforge.net>
- debian packaging
- various fixes
......
......@@ -26,9 +26,14 @@ bin_SCRIPTS = gstreamer-config
m4datadir = $(datadir)/aclocal
m4data_DATA = gstreamer.m4
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = gstreamer.pc
man_MANS = gstreamer-config.1
EXTRA_DIST = gstreamer.spec.in gstreamer-config.in gstreamer.m4 LICENSE REQUIREMENTS $(man_MANS)
EXTRA_DIST = gstreamer.spec.in gstreamer-config.in gstreamer.m4 \
gstreamer.pc.in gstreamer-uninstall.pc.in \
LICENSE REQUIREMENTS ABOUT-NLS $(man_MANS)
dist-hook:
cp gstreamer.spec $(distdir)
......
......@@ -79,24 +79,9 @@ autoheader
autoconf
automake --add-missing
if [ "x$1" = "x--autogen-recurse" ];then
exit # the rest will happen later
fi
#for dir in `find * -name autogen.sh -print | grep -v '^autogen.sh$' | \
# sed 's/autogen.sh$//'`;do
# echo "Recursively running autogen.sh in $dir"
# pushd $dir > /dev/null
# ./autogen.sh --autogen-recurse "$@"
# popd > /dev/null
#done
# now remove the cache, because it can be considered dangerous in this case
rm -f config.cache
# For busy application developers (Hadess)
# ./configure --enable-maintainer-mode --enable-debug --enable-debug-verbose --disable-docs-build "$@"
./configure --enable-maintainer-mode --enable-plugin-srcdir --enable-debug --enable-debug-verbose "$@"
echo
......
......@@ -417,35 +417,75 @@ AC_SUBST(X_LIBS)
dnl Check for the Xv library
xvsave_LIBS=${LIBS}
AC_CHECK_LIB(Xv, XvQueryExtension, HAVE_LIBXV=yes, HAVE_LIBXV=no, $X_LIBS $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS)
AC_CHECK_LIB(Xv, XvQueryExtension,
HAVE_LIBXV=yes
AC_DEFINE(HAVE_LIBXV),
HAVE_LIBXV=no,
$X_LIBS $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS
)
LIBS=${xvsave_LIBS}
AC_CHECK_HEADER(X11/extensions/Xv.h, :, HAVE_LIBXV=no)
AC_CHECK_HEADER(X11/extensions/Xvlib.h, :, HAVE_LIBXV=no)
dnl Check for OSS audio
AC_CHECK_HEADER(sys/soundcard.h, HAVE_OSS=yes, HAVE_OSS=no)
AC_CHECK_HEADER(sys/soundcard.h,
AC_DEFINE(HAVE_OSS)
HAVE_OSS=yes, []
)
dnl Check for xaudio
AC_CHECK_HEADER(xaudio/decoder.h, HAVE_XAUDIO=yes, HAVE_XAUDIO=no)
AC_CHECK_HEADER(xaudio/decoder.h,
AC_DEFINE(HAVE_XAUDIO)
HAVE_XAUDIO="yes",
AC_MSG_WARN(
***** NOTE: These plugins won't be built: gstxa
)
HAVE_XAUDIO="no",
)
dnl Check for libmad
AC_MSG_CHECKING(MAD library)
AC_CHECK_LIB(mad, mad_decoder_finish, HAVE_LIBMAD=yes, HAVE_LIBMAD=no, )
AC_CHECK_HEADER(mad.h, :, HAVE_LIBMAD=no)
AC_CHECK_LIB(mad, mad_decoder_finish,
HAVE_LIBMAD=yes
AC_DEFINE(HAVE_LIBMAD),
AC_MSG_WARN(
***** NOTE: These plugins won't be built: mad
)
HAVE_LIBMAD=no,
)
dnl Check for libvorbis
AC_MSG_CHECKING(Vorbis library)
AC_CHECK_LIB(vorbis, ogg_sync_init, HAVE_VORBIS=yes, HAVE_VORBIS=no, )
AC_CHECK_HEADER(vorbis/codec.h, :, HAVE_VORBIS=no)
AC_CHECK_LIB(vorbis, ogg_sync_init,
HAVE_VORBIS=yes
AC_DEFINE(HAVE_VORBIS),
AC_MSG_WARN(
***** NOTE: These plugins won't be built: vorbisdec vorbisenc
)
HAVE_VORBIS=no,
)
dnl Check for libjpeg
AC_MSG_CHECKING(libjpeg library)
AC_CHECK_LIB(jpeg, jpeg_set_defaults, HAVE_LIBJPEG=yes, HAVE_LIBJPEG=no, )
AC_CHECK_HEADER(jpeglib.h, :, HAVE_LIBJPEG=no)
AC_CHECK_LIB(jpeg, jpeg_set_defaults,
HAVE_LIBJPEG=yes
AC_DEFINE(HAVE_LIBJPEG),
AC_MSG_WARN(
***** NOTE: These plugins won't be built: jpegdec jpegenc
)
HAVE_LIBJPEG=no,
)
dnl Check for libHermes
dnl Check for Hermes
AC_MSG_CHECKING(Hermes library)
AC_CHECK_LIB(Hermes, Hermes_ConverterInstance, HAVE_LIBHERMES=yes, HAVE_LIBHERMES=no, )
AC_CHECK_LIB(Hermes, Hermes_ConverterInstance,
HAVE_LIBHERMES=yes
AC_DEFINE(HAVE_LIBHERMES),
AC_MSG_WARN(
***** NOTE: These plugins won't be built: colorspace
)
HAVE_LIBHERMES=no,
)
AC_CHECK_HEADER(Hermes/Hermes.h, :, HAVE_LIBHERMES=no)
dnl Check for cdparanoia
......@@ -672,13 +712,13 @@ esac],
[:]) dnl Default value
AC_ARG_ENABLE(docs-build,
[ --disable-docs-build disable all building of documentation],
[ --enable-docs-build enable building of documentation],
[case "${enableval}" in
yes) BUILD_DOCS=yes ;;
no) BUILD_DOCS=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-docs-build) ;;
esac],
[BUILD_DOCS=yes]) dnl Default value
[BUILD_DOCS=no]) dnl Default value
AC_ARG_ENABLE(plugin-docs,
[ --enable-plugin-docs enable the building of plugin documentation
......@@ -889,7 +929,11 @@ dnl ##############################
dnl # Set up the defaults cflags #
dnl ##############################
dnl CC="kgcc"
CFLAGS="$CORE_CFLAGS $CFLAGS -O6 -Wall"
if test "x$USE_PROFILING" = xyes; then
CFLAGS="$CORE_CFLAGS $CFLAGS -Wall"
else
CFLAGS="$CORE_CFLAGS $CFLAGS -O6 -Wall"
fi
LIBS="$CORE_LIBS $LIBS"
AC_SUBST(CORE_LIBS)
AC_SUBST(CORE_CFLAGS)
......@@ -1041,6 +1085,7 @@ tests/Makefile
tests/sched/Makefile
tests/eos/Makefile
testsuite/Makefile
testsuite/refcounting/Makefile
testsuite/capsnego/Makefile
tests/nego/Makefile
examples/Makefile
......@@ -1073,5 +1118,7 @@ docs/fwg/Makefile
debian/Makefile
stamp.h
gstreamer-config
gstreamer.spec])
gstreamer.spec
gstreamer.pc
gstreamer-uninstalled.pc])
AC_OUTPUT_COMMANDS([chmod +x gstreamer-config])
......@@ -61,9 +61,9 @@ The maximum number of cothreads we are going to support.
@argv:
@flags:
@sp:
@jmp:
@top_sp:
@pc:
@jmp:
<!-- ##### STRUCT cothread_context ##### -->
<para>
......
......@@ -267,24 +267,6 @@ circumstances.
@Returns:
<!-- ##### FUNCTION gst_element_set_manager ##### -->
<para>
</para>
@element:
@manager:
<!-- ##### FUNCTION gst_element_get_manager ##### -->
<para>
</para>
@element:
@Returns:
<!-- ##### FUNCTION gst_element_set_parent ##### -->
<para>
......
......@@ -46,3 +46,8 @@ The <classname>GstFakeSrc</classname> generates empty buffers. (fakesrc)
</para>
<!-- ##### ARG GstFakeSrc:eos ##### -->
<para>
</para>
......@@ -24,8 +24,10 @@ Thread flags:
</para>
@GST_THREAD_CREATE: The thread is being created.
@GST_THREAD_STATE_STARTED:
@GST_THREAD_STATE_SPINNING: The thread is runnning
@GST_THREAD_STATE_REAPING: The thread is ending.
@GST_THREAD_STATE_ELEMENT_CHANGED:
@GST_THREAD_FLAG_LAST: subclass use this to start their enumeration
<!-- ##### STRUCT GstThread ##### -->
......
-----------------------------------------------------------
- GStreamer Scheduling / Synchronization (incsched) Notes -
-----------------------------------------------------------
These notes describe deadlock scenarios and proposed solutions for
GStreamer. This will be implemented in the INCSCHED1 branch.
I. Miscelaneous proposals
II. Liveness problems (sometimes deadlock ;) and propsed solutions
III. State transition approach and responsibility
MattH.
--------------------------------
- I. Miscalenous proposals -
--------------------------------
1. Change the names of GstThread and GstQueue to GstPtThread and GstPtQueue
for pthread versions of Thread and Queue.
2. Change GstPtQueue to check its pads' peers' managers and make sure
they are different. If not, fail and generate error message. (This
ensures a GstPtQueue straddles a pthread boundary.)
3. Change state transitions to NULL <-> READY <-> PAUSED <-> PLAYING.
---------------------------------------------------
- II. Deadlock Scenarios and Proposed Solutions -
- (in the order they will be implemented) -
---------------------------------------------------
1. A downstream element "waits" for a buffer from its upstream element,
a state change happens and "pauses" the upstream element -- the
downstream element is blocked and cannot execute its change_state.
Note that this can only happen within a single GstPtQueue! Either a
downstream element calls Pull, finds no buffer, and does a
wait_cond(new buffer) or an upstream element calls Push, finds no
room, and does a wait_cond(new room). Thus, GstPtQueue contains all
the cond_wait / signal code.
=> The managing container (thread, pipeline) "wakes" up any sleep
conditions of its "bottom half". (In the scenario described, it
wakes the blocked downstream element's call to Pull.) The GstPtQueue
cond_wait section determines that it woke up due to a pending state
change and does a cothread_switch(0) to return to the main loop,
which then executes the state transition.
Note that a managing container will have only one sleep condition
in its "bottom half."
2. Element "blocked" on getting I/O and cannot execute its change_state.
=> We will provide an I/O library for the elements to use that does
not actually block. (A retry-loop with timeout or select() on
2 -- or more -- file descriptors: one the one you want I/O from,
the other one that GStreamer uses to "wake" everyone up.) The
I/O library determines that it was woken due to a pending state
change and does a cothread_switch(0) to return to the main loop,
which then executes the state transition.
Note that a managing container will have only one elements in
the middle of doing blocking I/O.
3. Element using a library (code out of its control) which blocks for
some reason (e.g., using real blocking I/O) so main loop never gets
run to execute change_state.
=> Build in some timeout in the manging container (the "top half")
when waiting for bottom half to respond to pending state. If
managing container times out, kill the element's thread with a
signal (or series of signals -- escalating priority). This
requires that the element (the "bottom half") have matching
signal handler(s) that execute(s) the state-transition.
--------------------------------------------------------
- III. State-transition Approach and Responsibility -
--------------------------------------------------------
A. The "top half" context of the managing container. (This is likely the
context of the application.)
Call change_state on the managing container (GstPipeline, GstPtThread).
If its "bottom half" (main_loop) is asleep, signal the condition to
wake it up. Then do a cond_wait for the "bottom half" to execute the
state transition and return (once the state has been changed).
B. The main_loop (the "bottom half") of the managing container.
Needs to check for pending state transition after every switch back from
one of its elements. If a pending state is found, it calls change_state
on each of its elements, signals the "top half" that the state has been
changed, then continues executing the plan (if Playing) or puts itself
to sleep (Paused, Ready).
C. Element.
Implement a change_state function to make transition for that element.
The elements' change_state is what actually changes the state variable
and notifies the scheduler that the state was changed. This function
may also do things like close or open resources.
NOTE: when an element goes through certain state transitions (e.g., from
Paused to Ready) its state (stack) will be wiped out. If it wants to
preserve any state or data, it needs to store the information in a safe
place.
D. Cothread Scheduler.
Gets notified of state transition by elements' change_state functions
then (re)set the plan accordingly. Assuming
NULL <-> READY <-> PAUSED <-> PLAYING, some would be
+ Paused -> Playing: jump back where you were in the Plan and continue
its execution
+ Ready -> Paused: reset the cothread pointers foreach cothread in the
Plan (don't run)
......@@ -8,4 +8,4 @@ endif
SUBDIRS = $(GNOME_SUBDS) \
helloworld helloworld2 \
queue queue2 queue3 queue4 \
launch thread xml plugins typefind
launch thread xml plugins typefind mixer
......@@ -2,94 +2,36 @@
#include <gnome.h>
static void
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
autoplug_have_size (GstElement *element, guint width, guint height,
GtkWidget *socket)
{
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
*(gboolean *)data = TRUE;
}
gboolean
idle_func (gpointer data)
{
return gst_bin_iterate (GST_BIN (data));
}
static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element)
{
gboolean found = FALSE;
GstElement *typefind;
GstCaps *caps = NULL;
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
GST_ELEMENT_NAME(element), &found);
typefind = gst_elementfactory_make ("typefind", "typefind");
g_return_val_if_fail (typefind != NULL, FALSE);
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
gst_pad_connect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_add (bin, typefind);
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
// push a buffer... the have_type signal handler will set the found flag
gst_bin_iterate (bin);
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
gst_pad_disconnect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_remove (bin, typefind);
gst_object_unref (GST_OBJECT (typefind));
return caps;
gtk_widget_set_usize(socket,width,height);
}
int main(int argc,char *argv[])
static void
gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
{
GstElement *disksrc, *osssink, *videosink;
GstElement *bin;
GstElement *osssink, *videosink;
GtkWidget *appwindow;
GstCaps *srccaps;
GstElement *new_element;
GstAutoplug *autoplug;
GtkWidget *socket;
GstElement *autobin;
GstElement *disksrc;
GstElement *cache;
g_thread_init(NULL);
gst_init(&argc,&argv);
gnome_init("autoplug","0.0.1", argc,argv);
if (argc != 2) {
g_print("usage: %s <filename>\n", argv[0]);
exit(-1);
}
/* create a new bin to hold the elements */
bin = gst_pipeline_new("pipeline");
g_assert(bin != NULL);
/* create a disk reader */
disksrc = gst_elementfactory_make("disksrc", "disk_source");
g_assert(disksrc != NULL);
gtk_object_set(GTK_OBJECT(disksrc),"location", argv[1],NULL);
GST_DEBUG (0,"GstPipeline: play have type\n");
gst_bin_add (GST_BIN (bin), disksrc);
gst_element_set_state (pipeline, GST_STATE_PAUSED);
srccaps = gst_play_typefind (GST_BIN (bin), disksrc);
disksrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source");
autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
if (!srccaps) {
g_print ("could not autoplug, unknown media type...\n");
exit (-1);
}
// disconnect the typefind from the pipeline and remove it
gst_element_disconnect (cache, "src", typefind, "sink");
gst_bin_remove (GST_BIN (autobin), typefind);
/* and an audio sink */
osssink = gst_elementfactory_make("osssink", "play_audio");
g_assert(osssink != NULL);
......@@ -102,7 +44,7 @@ int main(int argc,char *argv[])
g_assert (autoplug != NULL);
new_element = gst_autoplug_to_renderers (autoplug,
srccaps,
caps,
videosink,
osssink,
NULL);
......@@ -112,42 +54,122 @@ int main(int argc,char *argv[])
exit (-1);
}
gst_bin_remove (GST_BIN (bin), disksrc);
// FIXME hack, reparent the disksrc so the scheduler doesn't break
bin = gst_pipeline_new("pipeline");
gst_element_set_name (new_element, "new_element");
gst_bin_add (GST_BIN (bin), disksrc);
gst_bin_add (GST_BIN (bin), new_element);
gst_bin_add (GST_BIN (autobin), new_element);
gst_element_connect (disksrc, "src", new_element, "sink");
gtk_object_set (GTK_OBJECT (cache), "reset", TRUE, NULL);
appwindow = gnome_app_new("autoplug demo","autoplug demo");
gst_element_connect (cache, "src", new_element, "sink");
appwindow = gnome_app_new ("autoplug demo","autoplug demo");
socket = gtk_socket_new ();
gtk_widget_show (socket);
gnome_app_set_contents(GNOME_APP(appwindow),
gnome_app_set_contents (GNOME_APP (appwindow),
GTK_WIDGET (socket));
gtk_widget_realize (socket);
gtk_socket_steal (GTK_SOCKET (socket),
gst_util_get_int_arg (GTK_OBJECT (videosink), "xid"));
gtk_widget_set_usize(socket,320,240);
gtk_widget_show_all(appwindow);
gtk_widget_show_all (appwindow);
xmlSaveFile("xmlTest.gst", gst_xml_write(GST_ELEMENT(bin)));
gtk_signal_connect (GTK_OBJECT (videosink), "have_size",
GTK_SIGNAL_FUNC (autoplug_have_size), socket);
/* start playing */
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_PLAYING);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
xmlSaveFile("xmlTest.gst", gst_xml_write (GST_ELEMENT (pipeline)));
}
gboolean
idle_func (gpointer data)
{
return gst_bin_iterate (GST_BIN (data));
}
static void
gst_play_cache_empty (GstElement *element, GstElement *pipeline)
{
GstElement *autobin;
GstElement *disksrc;
GstElement *cache;
GstElement *new_element;
fprintf (stderr, "have cache empty\n");
gst_element_set_state (pipeline, GST_STATE_PAUSED);
disksrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source");
autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
gst_element_disconnect (disksrc, "src", cache, "sink");
gst_element_disconnect (cache, "src", new_element, "sink");
gst_bin_remove (GST_BIN (autobin), cache);
gst_element_connect (disksrc, "src", new_element, "sink");
gst_element_set_state (pipeline, GST_STATE_PLAYING);
fprintf (stderr, "done with cache_empty\n");
}
int main(int argc,char *argv[])
{
GstElement *disksrc;
GstElement *pipeline;
GstElement *autobin;
GstElement *typefind;
GstElement *cache;
g_thread_init(NULL);
gst_init(&argc,&argv);
gnome_init("autoplug","0.0.1", argc,argv);
if (argc != 2) {
g_print("usage: %s <filename>\n", argv[0]);
exit(-1);
}
/* create a new pipeline to hold the elements */
pipeline = gst_pipeline_new("pipeline");
g_assert(pipeline != NULL);
gtk_idle_add(idle_func, bin);
/* create a disk reader */
disksrc = gst_elementfactory_make("disksrc", "disk_source");
g_assert(disksrc != NULL);
gtk_object_set(GTK_OBJECT(disksrc),"location", argv[1],NULL);
gst_bin_add (GST_BIN (pipeline), disksrc);
autobin = gst_bin_new ("autobin");
cache = gst_elementfactory_make ("autoplugcache", "cache");
gtk_signal_connect (GTK_OBJECT (cache), "cache_empty", GTK_SIGNAL_FUNC (gst_play_cache_empty), pipeline);
typefind = gst_elementfactory_make ("typefind", "typefind");
gtk_signal_connect (GTK_OBJECT (typefind), "have_type", GTK_SIGNAL_FUNC (gst_play_have_type), pipeline);
gst_bin_add (GST_BIN (autobin), cache);
gst_bin_add (GST_BIN (autobin), typefind);
gst_element_connect (cache, "src", typefind, "sink");
gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink");
gst_bin_add (GST_BIN( pipeline), autobin);
gst_element_connect (disksrc, "src", autobin, "sink");
/* start playing */
gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING);
gst_main();
gtk_idle_add (idle_func, pipeline);
gst_main ();
/* stop the bin */
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_NULL);
/* stop the pipeline */
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
gst_pipeline_destroy(bin);
gst_object_unref (GST_OBJECT (pipeline));
exit(0);
}
......
......@@ -4,10 +4,13 @@
* demonstrates the adder plugin and the volume envelope plugin
* work in progress but do try it out
*
* Latest change : 16/04/2001
* multiple input channels allowed
* volume envelope adapted
* Version : 0.3
* Latest change : 28/04/2001
* trying to adapt to incsched
* delayed start for channels > 1
* now works by quickhacking the
* adder plugin to set
* GST_ELEMENT_COTHREAD_STOPPING
* Version : 0.5
*/
#include <stdlib.h>
......@@ -15,8 +18,10 @@
#include "mixer.h"
#include <unistd.h>
//#define WITH_BUG
//#define WITH_BUG2
//#define DEBUG
//#define AUTOPLUG /* define if you want autoplugging of input channels */
/* function prototypes */
input_channel_t* create_input_channel (int id, char* location);
......@@ -35,55 +40,50 @@ void eos(GstElement *element)
// playing = FALSE;
}
static void
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
{
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
*(gboolean *)data = TRUE;
}
static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element)
{
gboolean found = FALSE;
GstElement *typefind;
GstElement *pipeline;
GstCaps *caps = NULL;
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
GST_ELEMENT_NAME(element), &found);
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\"\n",
GST_ELEMENT_NAME(element));
pipeline = gst_pipeline_new ("autoplug_pipeline");
typefind = gst_elementfactory_make ("typefind", "typefind");
g_return_val_if_fail (typefind != NULL, FALSE);
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
gst_pad_connect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_add (bin, typefind);
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (bin));
gst_element_set_state (GST_ELEMENT (bin