Merged from INCSCHED on 200505251!!! INCSCHED1-200105251
authorErik Walthinsen <omega@temple-baptist.org>
Fri, 25 May 2001 21:00:07 +0000 (21:00 +0000)
committerErik Walthinsen <omega@temple-baptist.org>
Fri, 25 May 2001 21:00:07 +0000 (21:00 +0000)
Original commit message from CVS:
Merged from INCSCHED on 200505251!!!

111 files changed:
.gitignore
AUTHORS
Makefile.am
autogen.sh
configure.in
docs/gst/tmpl/cothreads.sgml
docs/gst/tmpl/gstelement.sgml
docs/gst/tmpl/gstfakesrc.sgml
docs/gst/tmpl/gstthread.sgml
docs/random/matth/scheduling.txt [new file with mode: 0644]
examples/Makefile.am
examples/autoplug/autoplug.c
examples/mixer/mixer.c
gst/Makefile.am
gst/autoplug/Makefile.am
gst/autoplug/autoplugtest.c [new file with mode: 0644]
gst/autoplug/gstautoplugcache.c [new file with mode: 0644]
gst/autoplug/gstautoplugger.c [new file with mode: 0644]
gst/autoplug/gststaticautoplug.c
gst/autoplug/gststaticautoplugrender.c
gst/cothreads.c
gst/cothreads.h
gst/elements/gstfakesrc.c
gst/elements/gstfakesrc.h
gst/elements/gstsinesrc.c
gst/gst.c
gst/gst.h
gst/gstbin.c
gst/gstbin.h
gst/gstbuffer.c
gst/gstcaps.c
gst/gstclock.c
gst/gstelement.c
gst/gstelement.h
gst/gstelementfactory.c
gst/gstinfo.c
gst/gstinfo.h
gst/gstobject.c
gst/gstobject.h
gst/gstpad.c
gst/gstpad.h
gst/gstpipeline.c
gst/gstprops.c
gst/gstqueue.c
gst/gstqueue.h
gst/gstscheduler.c
gst/gstscheduler.h
gst/gstthread.c
gst/gstthread.h
gst/gsttype.c
gst/gsttypefind.c
gst/gsttypes.h [new file with mode: 0644]
gst/gstxml.c
gstplay/Makefile.am
gstplay/gstmediaplay.c
gstplay/gstmediaplay.glade
gstplay/gstplay.c
gstplay/gstplay.h
gstplay/gstplayprivate.h
gstreamer-uninstalled.pc.in [new file with mode: 0644]
gstreamer.pc.in [new file with mode: 0644]
gstreamer.spec.in
libs/idct/gstidct.c
plugins/elements/gstfakesrc.c
plugins/elements/gstfakesrc.h
plugins/elements/gstqueue.c
plugins/elements/gstqueue.h
plugins/elements/gstsinesrc.c
test/.gitignore
test/Makefile.am
test/avi2mpg.c
test/cobin.c
test/dvshow.c
test/fake.c
test/mpeg2parse2.c
test/mpeg2parse3.c
test/mpeg2parse4.c [new file with mode: 0644]
test/video2mp1.c
test/videotest2.c
tests/Makefile.am
tests/incsched.c [new file with mode: 0644]
tests/mp1vid.c [new file with mode: 0644]
tests/old/examples/Makefile.am
tests/old/examples/autoplug/autoplug.c
tests/old/examples/mixer/mixer.c
tests/old/testsuite/refcounting/Makefile.am [new file with mode: 0644]
tests/old/testsuite/refcounting/bin.c [new file with mode: 0644]
tests/old/testsuite/refcounting/element.c [new file with mode: 0644]
tests/old/testsuite/refcounting/element_pad.c [new file with mode: 0644]
tests/old/testsuite/refcounting/mem.c [new file with mode: 0644]
tests/old/testsuite/refcounting/mem.h [new file with mode: 0644]
tests/old/testsuite/refcounting/object.c [new file with mode: 0644]
tests/old/testsuite/refcounting/pad.c [new file with mode: 0644]
tests/old/testsuite/refcounting/thread.c [new file with mode: 0644]
tests/reaping.c [new file with mode: 0644]
tests/states.c
tests/threadlock.c [new file with mode: 0644]
testsuite/refcounting/Makefile.am [new file with mode: 0644]
testsuite/refcounting/bin.c [new file with mode: 0644]
testsuite/refcounting/element.c [new file with mode: 0644]
testsuite/refcounting/element_pad.c [new file with mode: 0644]
testsuite/refcounting/mem.c [new file with mode: 0644]
testsuite/refcounting/mem.h [new file with mode: 0644]
testsuite/refcounting/object.c [new file with mode: 0644]
testsuite/refcounting/pad.c [new file with mode: 0644]
testsuite/refcounting/thread.c [new file with mode: 0644]
tools/.gitignore
tools/Makefile.am
tools/gstreamer-complete.c [new file with mode: 0644]
tools/gstreamer-compprep.c [new file with mode: 0644]
tools/gstreamer-inspect.c

index 320b264..a7d8dfa 100644 (file)
@@ -11,6 +11,8 @@ config.sub
 configure
 gstreamer-[0-9]*
 gstreamer-config
+gstreamer.pc
+gstreamer-uninstalled.pc
 gstreamer.spec
 libtool
 ltconfig
diff --git a/AUTHORS b/AUTHORS
index 2e4f2e6..4105ade 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -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
index ebdf9fb..14cbc0d 100644 (file)
@@ -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)
index e674cdf..1a0a240 100755 (executable)
@@ -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 
index 17c1c53..5f56a4d 100644 (file)
@@ -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])
index 4e5e52d..8131449 100644 (file)
@@ -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>
index 05b2def..f1471bd 100644 (file)
@@ -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>
 
index dfda3f4..197eaeb 100644 (file)
@@ -46,3 +46,8 @@ The <classname>GstFakeSrc</classname> generates empty buffers. (fakesrc)
 
 </para>
 
+<!-- ##### ARG GstFakeSrc:eos ##### -->
+<para>
+
+</para>
+
index a9e6652..bc4f3af 100644 (file)
@@ -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 ##### -->
diff --git a/docs/random/matth/scheduling.txt b/docs/random/matth/scheduling.txt
new file mode 100644 (file)
index 0000000..7b82d1d
--- /dev/null
@@ -0,0 +1,125 @@
+-----------------------------------------------------------
+- 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)
index c251eab..a970883 100644 (file)
@@ -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
index e9135fb..70ac4b7 100644 (file)
@@ -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);
 }
index 205d073..4461d47 100644 (file)
@@ -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>
 #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), GST_STATE_PLAYING);
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
   
   // push a buffer... the have_type signal handler will set the found flag
-  gst_bin_iterate (bin);
+  gst_bin_iterate (GST_BIN (pipeline));
   
-  gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
+  gst_element_set_state (pipeline, 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_bin_remove (GST_BIN (pipeline), GST_ELEMENT (bin));
   gst_object_unref (GST_OBJECT (typefind));
+  gst_object_unref (GST_OBJECT (pipeline));
                    
   return caps;
 }
 
 int main(int argc,char *argv[]) 
 {
-  int i;
+  int i, j;
   int num_channels;
+  gboolean done;
   
   char buffer[20];
   
@@ -108,38 +108,41 @@ int main(int argc,char *argv[])
   /* set up output channel and main bin */
   
   /* create adder */
-  adder = gst_elementfactory_make("adder", "adderel");
+  adder = gst_elementfactory_make ("adder", "adderel");
 
   /* create an audio sink */
-  audiosink = gst_elementfactory_make("esdsink", "play_audio");
+  audiosink = gst_elementfactory_make ("esdsink", "play_audio");
 
   /* create main bin */
-  main_bin = gst_bin_new("bin");
+  main_bin = gst_pipeline_new("bin");
 
   /* connect adder and output to bin */
-
-  gst_bin_add(GST_BIN(main_bin), adder);
-  gst_bin_add(GST_BIN(main_bin), audiosink);
+  GST_INFO (0, "main: adding adder to bin");
+  gst_bin_add (GST_BIN(main_bin), adder);
+  GST_INFO (0, "main: adding audiosink to bin");
+  gst_bin_add (GST_BIN(main_bin), audiosink);
 
   /* connect adder and audiosink */
 
   gst_pad_connect(gst_element_get_pad(adder,"src"),
                   gst_element_get_pad(audiosink,"sink"));
   
-  /* create input channels, add to bin and connect */
-
+  /* start looping */
   input_channels = NULL;
   
   for (i = 1; i < argc; ++i)
   {
     printf ("Opening channel %d from file %s...\n", i, argv[i]);
     channel_in = create_input_channel (i, argv[i]);
-    input_channels = g_list_append (input_channels, channel_in);  
-    gst_bin_add(GST_BIN(main_bin), channel_in->pipe);
+    input_channels = g_list_append (input_channels, channel_in);
+
+    if (i > 1) gst_element_set_state (main_bin, GST_STATE_PAUSED);
+    gst_bin_add (GST_BIN(main_bin), channel_in->pipe);
 
     /* request pads and connect to adder */
+    GST_INFO (0, "requesting pad\n");
     pad = gst_element_request_pad_by_name (adder, "sink%d");
-    g_print ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
+    printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
     sprintf (buffer, "channel%d", i);
     gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad);
 
@@ -178,24 +181,32 @@ int main(int argc,char *argv[])
       env_register_cp (channel_in->volenv,  num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */
     }   
     env_register_cp (channel_in->volenv,  num_channels * 10.0      , 1.0 / num_channels); /* to end level */
-  }
-
-  /* sleep a few seconds doesn't seem to help anyway */
 
-  printf ("Sleeping a few seconds ...\n");
-  sleep (2);
-  printf ("Waking up ...\n");
+    xmlSaveFile("mixer.xml", gst_xml_write(GST_ELEMENT(main_bin)));
 
-  
-  /* start playing */
-  gst_element_set_state(main_bin, GST_STATE_PLAYING);
+    /* start playing */
+    gst_element_set_state(main_bin, GST_STATE_PLAYING);
 
-  playing = TRUE;
+    // write out the schedule
+    gst_schedule_show(GST_ELEMENT_SCHED(main_bin));
+    playing = TRUE;
 
-  while (playing) {
+    j = 0;
+    //printf ("main: start iterating from 0");
+    while (playing && j < 100) 
+    {
+//      printf ("main: iterating %d\n", j);
+      gst_bin_iterate(GST_BIN(main_bin));
+     //fprintf(stderr,"after iterate()\n");
+      ++j;
+    }
+  }
+  printf ("main: all the channels are open\n");
+  while (playing) 
+  {
     gst_bin_iterate(GST_BIN(main_bin));
+    //fprintf(stderr,"after iterate()\n");
   }
-
   /* stop the bin */
   gst_element_set_state(main_bin, GST_STATE_NULL);
 
@@ -228,11 +239,10 @@ create_input_channel (int id, char* location)
   GstAutoplug *autoplug;
   GstCaps *srccaps;
   GstElement *new_element;  
+  GstElement *decoder;
 
-#ifdef DEBUG
-  printf ("DEBUG : c_i_p : creating channel with id %d for file %s\n",
+  GST_DEBUG (0, "c_i_p : creating channel with id %d for file %s\n",
                  id, location);
-#endif
   
   /* allocate channel */
 
@@ -245,23 +255,21 @@ create_input_channel (int id, char* location)
 
   /* create channel */
 
-#ifdef DEBUG
-  printf ("DEBUG : c_i_p : creating pipeline\n");
-#endif
+  GST_DEBUG (0, "c_i_p : creating pipeline\n");
 
-  channel->pipe = gst_bin_new ("pipeline");
+  sprintf (buffer, "pipeline%d", id);
+  channel->pipe = gst_bin_new (buffer);
   g_assert(channel->pipe != NULL);    
     
   /* create elements */
 
-#ifdef DEBUG
-  printf ("DEBUG : c_i_p : creating disksrc\n");
-#endif
+  GST_DEBUG(0, "c_i_p : creating disksrc\n");
 
   sprintf (buffer, "disksrc%d", id);
   channel->disksrc = gst_elementfactory_make ("disksrc", buffer);
   g_assert(channel->disksrc != NULL);    
-  
+
+  GST_DEBUG(0, "c_i_p : setting location\n");
   gtk_object_set(GTK_OBJECT(channel->disksrc),"location", location, NULL);
 
   /* add disksrc to the bin before autoplug */
@@ -286,8 +294,24 @@ create_input_channel (int id, char* location)
   printf ("DEBUG : c_i_p : getting srccaps\n");
 #endif
 
+#ifdef WITH_BUG
   srccaps = gst_play_typefind (GST_BIN (channel->pipe), channel->disksrc);
+#endif
+#ifdef WITH_BUG2
+  {
+    GstElement *pipeline;
 
+    pipeline = gst_pipeline_new ("autoplug_pipeline");
+
+    gst_bin_add (GST_BIN (pipeline), channel->pipe);
+    gst_element_set_state (pipeline, GST_STATE_PLAYING);
+    gst_element_set_state (pipeline, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (pipeline), channel->pipe);
+    
+  }
+#endif
+
+#ifdef AUTOPLUG
   if (!srccaps) {
     g_print ("could not autoplug, unknown media type...\n");
     exit (-1);
@@ -311,7 +335,24 @@ create_input_channel (int id, char* location)
     g_print ("could not autoplug, no suitable codecs found...\n");
     exit (-1);
   }
+
+#else
+
+  new_element = gst_bin_new ("autoplug_bin");
+
+  /* static plug, use mad plugin and assume mp3 input */
+  decoder =  gst_elementfactory_make ("mad", "mpg123");
+
+  gst_bin_add (GST_BIN (new_element), decoder);
+
+  gst_element_add_ghost_pad (new_element, 
+                 gst_element_get_pad (decoder, "sink"), "sink");
+  gst_element_add_ghost_pad (new_element, 
+                 gst_element_get_pad (decoder, "src"), "src_00");
   
+#endif  
+  xmlSaveFile ("mixer.gst", gst_xml_write (new_element));
+
   gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
   gst_bin_add (GST_BIN (channel->pipe), new_element);
   
index cfd5ac6..edd8c0d 100644 (file)
@@ -90,6 +90,7 @@ libgstincludedir = $(includedir)/gst
 libgstinclude_HEADERS =                \
        cothreads.h             \
        gst.h                   \
+       gsttypes.h              \
        gstautoplug.h           \
        gstbin.h                \
        gstbuffer.h             \
@@ -128,7 +129,7 @@ noinst_HEADERS =    \
        gstsparc.h      \
        gstpropsprivate.h
 
-CFLAGS = $(LIBGST_CFLAGS)
+CFLAGS = $(LIBGST_CFLAGS) -D_GNU_SOURCE
 LIBS = $(LIBGST_LIBS)
 libgst_la_LDFLAGS = -version-info $(GST_LIBVERSION)
 
index 8050727..043317a 100644 (file)
@@ -1,6 +1,7 @@
 filterdir = $(libdir)/gst
 
-filter_LTLIBRARIES = libgststaticautoplug.la libgststaticautoplugrender.la
+filter_LTLIBRARIES = libgststaticautoplug.la libgststaticautoplugrender.la \
+       libgstautoplugcache.la libgstautoplugger.la
 
 libgststaticautoplug_la_SOURCES =      \
        gststaticautoplug.c 
@@ -8,5 +9,12 @@ libgststaticautoplug_la_SOURCES =      \
 libgststaticautoplugrender_la_SOURCES =        \
        gststaticautoplugrender.c
 
+libgstautoplugcache_la_SOURCES = gstautoplugcache.c
+libgstautoplugger_la_SOURCES = gstautoplugger.c
+
 libgststaticautoplug_la_LDFLAGS = -version-info $(GST_LIBVERSION)
 libgststaticautoplugrender_la_LDFLAGS = -version-info $(GST_LIBVERSION)
+libgstautoplugcache_la_LDFLAGS = -version-info $(GST_LIBVERSION)
+
+noinst_PROGRAMS = autoplugtest
+autoplugtest_LDADD = $(GST_LIBS)
diff --git a/gst/autoplug/autoplugtest.c b/gst/autoplug/autoplugtest.c
new file mode 100644 (file)
index 0000000..748175f
--- /dev/null
@@ -0,0 +1,92 @@
+#include <gst/gst.h>
+#include <string.h>
+
+GstElement *pipeline, *src, *autobin, *cache, *typefind, *decoder, *sink;
+
+void cache_empty(GstElement *element, gpointer private) {
+  fprintf(stderr,"have cache empty\n");
+
+  gst_element_set_state (pipeline, GST_STATE_PAUSED);
+
+  gst_element_disconnect(src,"src",cache,"sink");
+  gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
+  gst_element_disconnect(cache,"src",decoder,"sink");
+  gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
+  gst_bin_remove (GST_BIN(autobin), cache);
+  gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
+  gst_element_connect(src,"src",decoder,"sink");
+  gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
+
+  fprintf(stderr,"done with cache_empty\n");
+}
+
+void have_type(GstElement *element, GstCaps *caps, GstCaps **private_caps) {
+  fprintf(stderr,"have caps, mime type is %s\n",gst_caps_get_mime(caps));
+
+  gst_element_set_state (pipeline, GST_STATE_PAUSED);
+
+  // disconnect the typefind from the pipeline and remove it
+  gst_element_disconnect(cache,"src",typefind,"sink");
+  gst_bin_remove(GST_BIN(autobin),typefind);
+
+  gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
+
+  if (strstr(gst_caps_get_mime(caps),"mp3")) {
+    decoder = gst_elementfactory_make ("mad","decoder");
+    sink = gst_elementfactory_make ("osssink","sink");
+    gst_bin_add(GST_BIN(autobin),decoder);
+    gst_bin_add(GST_BIN(autobin),sink);
+    gst_element_connect(decoder,"src",sink,"sink");
+
+    gtk_object_set (GTK_OBJECT(cache), "reset", TRUE, NULL);
+
+    gst_element_connect(cache,"src",decoder,"sink");
+  }
+  else if (strstr(gst_caps_get_mime(caps),"x-ogg")) {
+    decoder = gst_elementfactory_make ("vorbisdec","decoder");
+    sink = gst_elementfactory_make ("osssink","sink");
+    gst_bin_add(GST_BIN(autobin),decoder);
+    gst_bin_add(GST_BIN(autobin),sink);
+    gst_element_connect(decoder,"src",sink,"sink");
+
+    gtk_object_set (GTK_OBJECT(cache), "reset", TRUE, NULL);
+
+    gst_element_connect(cache,"src",decoder,"sink");
+  }
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  fprintf(stderr,"done with have_type signal\n");
+}
+
+int main (int argc,char *argv[]) {
+  GstCaps *caps;
+  int i;
+
+  gst_init(&argc,&argv);
+
+  pipeline = gst_pipeline_new("pipeline");
+  src = gst_elementfactory_make ("disksrc","src");
+  gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
+  gst_bin_add (GST_BIN(pipeline),src);
+
+  autobin = gst_bin_new("autobin");
+  cache = gst_elementfactory_make ("autoplugcache","cache");
+  gtk_signal_connect (GTK_OBJECT(cache),"cache_empty",GTK_SIGNAL_FUNC(cache_empty),NULL);
+  typefind = gst_elementfactory_make ("typefind", "typefind");
+  gtk_signal_connect (GTK_OBJECT(typefind),"have_type",GTK_SIGNAL_FUNC(have_type),&caps);
+  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 (src,"src",autobin,"sink");
+
+  gst_element_set_state(pipeline,GST_STATE_PLAYING);
+
+  while (1)
+    gst_bin_iterate(GST_BIN(pipeline));
+}
diff --git a/gst/autoplug/gstautoplugcache.c b/gst/autoplug/gstautoplugcache.c
new file mode 100644 (file)
index 0000000..0948672
--- /dev/null
@@ -0,0 +1,371 @@
+/* GStreamer
+ * Copyright (C) 2001 RidgeRun, Inc. (www.ridgerun.com)
+ *
+ * gstautoplugcache.c: Data cache for the dynamic autoplugger
+ *
+ * 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/gst.h>
+
+GstElementDetails gst_autoplugcache_details = {
+  "AutoplugCache",
+  "Connection",
+  "Data cache for the dynamic autoplugger",
+  VERSION,
+  "Erik Walthinsen <omega@temple-baptist.com>",
+  "(C) 2001 RidgeRun, Inc. (www.ridgerun.com)",
+};
+
+#define GST_TYPE_AUTOPLUGCACHE \
+  (gst_autoplugcache_get_type())
+#define GST_AUTOPLUGCACHE(obj) \
+  (GTK_CHECK_CAST((obj),GST_TYPE_AUTOPLUGCACHE,GstAutoplugCache))
+#define GST_AUTOPLUGCACHE_CLASS(klass) \
+  (GTK_CHECK_CLASS_CAST((klass),GST_TYPE_AUTOPLUGCACHE,GstAutoplugCacheClass))
+#define GST_IS_AUTOPLUGCACHE(obj) \
+  (GTK_CHECK_TYPE((obj),GST_TYPE_AUTOPLUGCACHE))
+#define GST_IS_AUTOPLUGCACHE_CLASS(obj) \
+  (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_AUTOPLUGCACHE))
+
+typedef struct _GstAutoplugCache GstAutoplugCache;
+typedef struct _GstAutoplugCacheClass GstAutoplugCacheClass;
+
+struct _GstAutoplugCache {
+  GstElement element;
+
+  GstPad *sinkpad, *srcpad;
+
+  gboolean caps_proxy;
+
+  GList *cache;
+  GList *cache_start;
+  gint buffer_count;
+  GList *current_playout;
+  gboolean fire_empty;
+  gboolean fire_first;
+};
+
+struct _GstAutoplugCacheClass {
+  GstElementClass parent_class;
+
+  void         (*first_buffer)         (GstElement *element, GstBuffer *buf);
+  void         (*cache_empty)          (GstElement *element);
+};
+
+
+/* Cache signals and args */
+enum {
+  FIRST_BUFFER,
+  CACHE_EMPTY,
+  LAST_SIGNAL
+};
+
+enum {
+  ARG_0,
+  ARG_BUFFER_COUNT,
+  ARG_CAPS_PROXY,
+  ARG_RESET
+};
+
+
+static void                    gst_autoplugcache_class_init    (GstAutoplugCacheClass *klass);
+static void                    gst_autoplugcache_init          (GstAutoplugCache *cache);
+
+static void                    gst_autoplugcache_set_arg       (GtkObject *object, GtkArg *arg, guint id);
+static void                    gst_autoplugcache_get_arg       (GtkObject *object, GtkArg *arg, guint id);
+
+static void                    gst_autoplugcache_loop          (GstElement *element);
+
+static GstPadNegotiateReturn    gst_autoplugcache_nego_src     (GstPad *pad, GstCaps **caps, gpointer *data);
+static GstPadNegotiateReturn    gst_autoplugcache_nego_sink    (GstPad *pad, GstCaps **caps, gpointer *data);
+static GstElementStateReturn   gst_autoplugcache_change_state  (GstElement *element);
+
+
+static GstElementClass *parent_class = NULL;
+static guint gst_autoplugcache_signals[LAST_SIGNAL] = { 0 };
+
+GtkType
+gst_autoplugcache_get_type(void) {
+  static GtkType autoplugcache_type = 0;
+
+  if (!autoplugcache_type) {
+    static const GtkTypeInfo autoplugcache_info = {
+      "GstAutoplugCache",
+      sizeof(GstAutoplugCache),
+      sizeof(GstAutoplugCacheClass),
+      (GtkClassInitFunc)gst_autoplugcache_class_init,
+      (GtkObjectInitFunc)gst_autoplugcache_init,
+      (GtkArgSetFunc)gst_autoplugcache_set_arg,
+      (GtkArgGetFunc)gst_autoplugcache_get_arg,
+      (GtkClassInitFunc)NULL,
+    };
+    autoplugcache_type = gtk_type_unique (GST_TYPE_ELEMENT, &autoplugcache_info);
+  }
+  return autoplugcache_type;
+}
+
+static void
+gst_autoplugcache_class_init (GstAutoplugCacheClass *klass)
+{
+  GtkObjectClass *gtkobject_class;
+  GstElementClass *gstelement_class;
+
+  gtkobject_class = (GtkObjectClass*)klass;
+  gstelement_class = (GstElementClass*)klass;
+
+  parent_class = gtk_type_class (GST_TYPE_ELEMENT);
+
+  gst_autoplugcache_signals[FIRST_BUFFER] =
+    gtk_signal_new ("first_buffer", GTK_RUN_LAST, gtkobject_class->type,
+                    GTK_SIGNAL_OFFSET (GstAutoplugCacheClass, first_buffer),
+                    gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
+                    GTK_TYPE_POINTER);
+  gst_autoplugcache_signals[CACHE_EMPTY] =
+    gtk_signal_new ("cache_empty", GTK_RUN_LAST, gtkobject_class->type,
+                    GTK_SIGNAL_OFFSET (GstAutoplugCacheClass, cache_empty),
+                    gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
+  gtk_object_class_add_signals (gtkobject_class, gst_autoplugcache_signals, LAST_SIGNAL);
+
+  gtk_object_add_arg_type ("GstAutoplugCache::buffer_count", GTK_TYPE_INT,
+                           GTK_ARG_READABLE, ARG_BUFFER_COUNT);
+  gtk_object_add_arg_type ("GstAutoplugCache::caps_proxy", GTK_TYPE_BOOL,
+                           GTK_ARG_READWRITE, ARG_CAPS_PROXY);
+  gtk_object_add_arg_type ("GstAutoplugCache::reset", GTK_TYPE_BOOL,
+                           GTK_ARG_WRITABLE, ARG_RESET);
+
+  gtkobject_class->set_arg = gst_autoplugcache_set_arg;
+  gtkobject_class->get_arg = gst_autoplugcache_get_arg;
+
+  gstelement_class->change_state = gst_autoplugcache_change_state;
+}
+
+static void
+gst_autoplugcache_init (GstAutoplugCache *cache)
+{
+  gst_element_set_loop_function(GST_ELEMENT(cache), GST_DEBUG_FUNCPTR(gst_autoplugcache_loop));
+
+  cache->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
+//  gst_pad_set_negotiate_function (cache->sinkpad, gst_autoplugcache_nego_sink);
+  gst_element_add_pad (GST_ELEMENT(cache), cache->sinkpad);
+
+  cache->srcpad = gst_pad_new ("src", GST_PAD_SRC);
+//  gst_pad_set_negotiate_function (cache->srcpad, gst_autoplugcache_nego_src);
+  gst_element_add_pad (GST_ELEMENT(cache), cache->srcpad);
+
+  cache->caps_proxy = FALSE;
+
+  // provide a zero basis for the cache
+  cache->cache = g_list_prepend(NULL, NULL);
+  cache->cache_start = cache->cache;
+  cache->buffer_count = 0;
+  cache->current_playout = 0;
+  cache->fire_empty = FALSE;
+  cache->fire_first = FALSE;
+}
+
+static void
+gst_autoplugcache_loop (GstElement *element)
+{
+  GstAutoplugCache *cache;
+  GstBuffer *buf = NULL;
+
+  cache = GST_AUTOPLUGCACHE (element);
+
+  /* Theory:
+   * The cache is a doubly-linked list.  The front of the list is the most recent
+   * buffer, the end of the list is the first buffer.  The playout pointer always
+   * points to the latest buffer sent out the end.  cache points to the front
+   * (most reccent) of the list at all times.  cache_start points to the first 
+   * buffer, i.e. the end of the list.
+   * If the playout pointer does not have a prev (towards the most recent) buffer 
+   * (== NULL), a buffer must be pulled from the sink pad and added to the cache.
+   * When the playout pointer gets reset (as in a set_arg), the cache is walked
+   * without problems, because the playout pointer has a non-NULL next.  When
+   * the playout pointer hits the end of cache again it has to start pulling.
+   */
+
+  do {
+    // the first time through, the current_playout pointer is going to be NULL
+    if (cache->current_playout == NULL) {
+      // get a buffer
+      buf = gst_pad_pull (cache->sinkpad);
+
+      // add it to the cache, though cache == NULL
+      gst_buffer_ref (buf);
+      cache->cache = g_list_prepend (cache->cache, buf);
+      cache->buffer_count++;
+
+      // set the current_playout pointer
+      cache->current_playout = cache->cache;
+
+      gtk_signal_emit (GTK_OBJECT(cache), gst_autoplugcache_signals[FIRST_BUFFER], buf);
+
+      // send the buffer on its way
+      gst_pad_push (cache->srcpad, buf);
+    }
+
+    // the steady state is where the playout is at the front of the cache
+    else if (g_list_previous(cache->current_playout) == NULL) {
+
+      // if we've been told to fire an empty signal (after a reset)
+      if (cache->fire_empty) {
+        int oldstate = GST_STATE(cache);
+        fprintf(stderr,"at front of cache, about to pull, but firing signal\n");
+        gst_object_ref (GST_OBJECT (cache));
+        gtk_signal_emit (GTK_OBJECT(cache), gst_autoplugcache_signals[CACHE_EMPTY], NULL);
+        if (GST_STATE(cache) != oldstate) {
+          gst_object_ref (GST_OBJECT (cache));
+          GST_DEBUG(GST_CAT_AUTOPLUG, "state changed during signal, aborting\n");
+          cothread_switch(cothread_current_main());
+        }
+        gst_object_unref (GST_OBJECT (cache));
+      }
+
+      // get a buffer
+      buf = gst_pad_pull (cache->sinkpad);
+
+      // add it to the front of the cache
+      gst_buffer_ref (buf);
+      cache->cache = g_list_prepend (cache->cache, buf);
+      cache->buffer_count++;
+
+      // set the current_playout pointer
+      cache->current_playout = cache->cache;
+
+      // send the buffer on its way
+      gst_pad_push (cache->srcpad, buf);
+    }
+
+    // otherwise we're trundling through existing cached buffers
+    else {
+      // move the current_playout pointer
+      cache->current_playout = g_list_previous (cache->current_playout);
+
+      if (cache->fire_first) {
+        gtk_signal_emit (GTK_OBJECT(cache), gst_autoplugcache_signals[FIRST_BUFFER], buf);
+        cache->fire_first = FALSE;
+      }
+
+      // push that buffer
+      gst_pad_push (cache->srcpad, GST_BUFFER(cache->current_playout->data));
+    }
+  } while (!GST_FLAG_IS_SET (element, GST_ELEMENT_COTHREAD_STOPPING));
+}
+
+static GstPadNegotiateReturn
+gst_autoplugcache_nego_src (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+  GstAutoplugCache *cache = GST_AUTOPLUGCACHE (GST_PAD_PARENT (pad));
+
+  return gst_pad_negotiate_proxy (pad, cache->sinkpad, caps);
+}
+
+static GstPadNegotiateReturn
+gst_autoplugcache_nego_sink (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+  GstAutoplugCache *cache = GST_AUTOPLUGCACHE (GST_PAD_PARENT (pad));
+
+  return gst_pad_negotiate_proxy (pad, cache->srcpad, caps);
+}
+
+
+static GstElementStateReturn
+gst_autoplugcache_change_state (GstElement *element)
+{
+  // FIXME this should do something like free the cache on ->NULL
+  if (GST_ELEMENT_CLASS (parent_class)->change_state)
+    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+  return GST_STATE_SUCCESS;
+}
+
+static void
+gst_autoplugcache_set_arg (GtkObject *object, GtkArg *arg, guint id)
+{
+  GstAutoplugCache *cache;
+
+  cache = GST_AUTOPLUGCACHE (object);
+
+  switch (id) {
+    case ARG_CAPS_PROXY:
+      cache->caps_proxy = GTK_VALUE_BOOL(*arg);
+GST_DEBUG(0,"caps_proxy is %d\n",cache->caps_proxy);
+      if (cache->caps_proxy) {
+        gst_pad_set_negotiate_function (cache->sinkpad, GST_DEBUG_FUNCPTR(gst_autoplugcache_nego_sink));
+        gst_pad_set_negotiate_function (cache->srcpad, GST_DEBUG_FUNCPTR(gst_autoplugcache_nego_src));
+      } else {
+        gst_pad_set_negotiate_function (cache->sinkpad, NULL);
+        gst_pad_set_negotiate_function (cache->srcpad, NULL);
+      }
+      break;
+    case ARG_RESET:
+      // no idea why anyone would set this to FALSE, but just in case ;-)
+      if (GTK_VALUE_BOOL(*arg)) {
+        fprintf(stderr,"resetting playout pointer\n");
+        // reset the playout pointer to the begining again
+        cache->current_playout = cache->cache_start;
+        // now we can fire a signal when the cache runs dry
+        cache->fire_empty = TRUE;
+        // also set it up to fire the first_buffer signal again
+        cache->fire_first = TRUE;
+      }
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_autoplugcache_get_arg (GtkObject *object, GtkArg *arg, guint id)
+{
+  GstAutoplugCache *cache;
+
+  cache = GST_AUTOPLUGCACHE (object);
+
+  switch (id) {
+    case ARG_BUFFER_COUNT:
+      GTK_VALUE_INT(*arg) = cache->buffer_count;
+      break;
+    case ARG_CAPS_PROXY:
+      GTK_VALUE_BOOL(*arg) = cache->caps_proxy;
+    default:
+      arg->type = GTK_TYPE_INVALID;
+      break;
+  }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+  GstElementFactory *factory;
+
+  factory = gst_elementfactory_new ("autoplugcache", GST_TYPE_AUTOPLUGCACHE,
+                                    &gst_autoplugcache_details);
+  g_return_val_if_fail (factory != NULL, FALSE);
+
+  gst_plugin_add_factory (plugin, factory);
+
+  return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+  GST_VERSION_MAJOR,
+  GST_VERSION_MINOR,
+  "autoplugcache",
+  plugin_init
+};
+
diff --git a/gst/autoplug/gstautoplugger.c b/gst/autoplug/gstautoplugger.c
new file mode 100644 (file)
index 0000000..883d8cd
--- /dev/null
@@ -0,0 +1,606 @@
+/* GStreamer
+ * Copyright (C) 2001 RidgeRun, Inc. (www.ridgerun.com)
+ *
+ * gstautoplugger.c: Data  for the dynamic autopluggerger
+ *
+ * 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/gst.h>
+
+GstElementDetails gst_autoplugger_details = {
+  "Dynamic autoplugger",
+  "Autoplugger",
+  "Magic element that converts from any type to any other",
+  VERSION,
+  "Erik Walthinsen <omega@temple-baptist.com>",
+  "(C) 2001 RidgeRun, Inc. (www.ridgerun.com)",
+};
+
+#define GST_TYPE_AUTOPLUGGER \
+  (gst_autoplugger_get_type())
+#define GST_AUTOPLUGGER(obj) \
+  (GTK_CHECK_CAST((obj),GST_TYPE_AUTOPLUGGER,GstAutoplugger))
+#define GST_AUTOPLUGGER_CLASS(klass) \
+  (GTK_CHECK_CLASS_CAST((klass),GST_TYPE_AUTOPLUGGER,GstAutopluggerClass))
+#define GST_IS_AUTOPLUGGER(obj) \
+  (GTK_CHECK_TYPE((obj),GST_TYPE_AUTOPLUGGER))
+#define GST_IS_AUTOPLUGGER_CLASS(obj) \
+  (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_AUTOPLUGGER))
+
+typedef struct _GstAutoplugger GstAutoplugger;
+typedef struct _GstAutopluggerClass GstAutopluggerClass;
+
+struct _GstAutoplugger {
+  GstBin bin;
+  gint paused;
+
+  GstElement *cache;
+  gboolean cache_first_buffer;
+  GstPad *cache_sinkpad, *cache_srcpad;
+
+  GstElement *typefind;
+  GstPad *typefind_sinkpad;
+
+  GstPad *sinkpadpeer, *srcpadpeer;
+  GstCaps *sinkcaps, *srccaps;
+
+  GstCaps *sinktemplatecaps;
+
+  GstAutoplug *autoplug;
+  GstElement *autobin;
+
+  gboolean disable_nocaps;
+};
+
+struct _GstAutopluggerClass {
+  GstBinClass parent_class;
+};
+
+
+/*  signals and args */
+enum {
+  LAST_SIGNAL
+};
+
+enum {
+  ARG_0,
+};
+
+
+static void                    gst_autoplugger_class_init      (GstAutopluggerClass *klass);
+static void                    gst_autoplugger_init            (GstAutoplugger *queue);
+
+static void                    gst_autoplugger_set_arg         (GtkObject *object, GtkArg *arg, guint id);
+static void                    gst_autoplugger_get_arg         (GtkObject *object, GtkArg *arg, guint id);
+
+//static GstElementStateReturn gst_autoplugger_change_state    (GstElement *element);
+
+
+static void    gst_autoplugger_external_sink_caps_changed      (GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger);
+static void    gst_autoplugger_external_src_caps_changed       (GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger);
+static void    gst_autoplugger_external_sink_caps_nego_failed  (GstPad *pad, gboolean *result, GstAutoplugger *autoplugger);
+static void    gst_autoplugger_external_src_caps_nego_failed   (GstPad *pad, gboolean *result, GstAutoplugger *autoplugger);
+static void    gst_autoplugger_external_sink_connected         (GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger);
+static void    gst_autoplugger_external_src_connected          (GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger);
+
+static void    gst_autoplugger_cache_first_buffer              (GstElement *element,GstBuffer *buf,GstAutoplugger *autoplugger);
+static void    gst_autoplugger_cache_empty                     (GstElement *element, GstAutoplugger *autoplugger);
+static void    gst_autoplugger_typefind_have_type              (GstElement *element, GstCaps *caps, GstAutoplugger *autoplugger);
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_autoplugger_signals[LAST_SIGNAL] = { 0 };
+
+GtkType
+gst_autoplugger_get_type(void) {
+  static GtkType autoplugger_type = 0;
+
+  if (!autoplugger_type) {
+    static const GtkTypeInfo autoplugger_info = {
+      "GstAutoplugger",
+      sizeof(GstAutoplugger),
+      sizeof(GstAutopluggerClass),
+      (GtkClassInitFunc)gst_autoplugger_class_init,
+      (GtkObjectInitFunc)gst_autoplugger_init,
+      (GtkArgSetFunc)gst_autoplugger_set_arg,
+      (GtkArgGetFunc)gst_autoplugger_get_arg,
+      (GtkClassInitFunc)NULL,
+    };
+    autoplugger_type = gtk_type_unique (GST_TYPE_BIN, &autoplugger_info);
+  }
+  return autoplugger_type;
+}
+
+static void
+gst_autoplugger_class_init (GstAutopluggerClass *klass)
+{
+  GtkObjectClass *gtkobject_class;
+  GstElementClass *gstelement_class;
+
+  gtkobject_class = (GtkObjectClass*)klass;
+  gstelement_class = (GstElementClass*)klass;
+
+  parent_class = gtk_type_class (GST_TYPE_ELEMENT);
+
+/*
+  gst_autoplugger_signals[_EMPTY] =
+    gtk_signal_new ("_empty", GTK_RUN_LAST, gtkobject_class->type,
+                    GTK_SIGNAL_OFFSET (GstAutopluggerClass, _empty),
+                    gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
+  gtk_object_class_add_signals (gtkobject_class, gst_autoplugger_signals, LAST_SIGNAL);
+*/
+
+/*
+  gtk_object_add_arg_type ("GstAutoplugger::buffer_count", GTK_TYPE_INT,
+                           GTK_ARG_READABLE, ARG_BUFFER_COUNT);
+  gtk_object_add_arg_type ("GstAutoplugger::reset", GTK_TYPE_BOOL,
+                           GTK_ARG_WRITABLE, ARG_RESET);
+*/
+
+  gtkobject_class->set_arg = gst_autoplugger_set_arg;
+  gtkobject_class->get_arg = gst_autoplugger_get_arg;
+
+//  gstelement_class->change_state = gst_autoplugger_change_state;
+}
+
+static void
+gst_autoplugger_init (GstAutoplugger *autoplugger)
+{
+  // create the autoplugger cache, which is the fundamental unit of the autopluggerger
+  // FIXME we need to find a way to set element's name before _init
+  // FIXME ... so we can name the subelements uniquely
+  autoplugger->cache = gst_elementfactory_make("autoplugcache", "unnamed_autoplugcache");
+  g_return_if_fail (autoplugger->cache != NULL);
+
+  GST_DEBUG(GST_CAT_AUTOPLUG, "turning on caps nego proxying in cache\n");
+  gtk_object_set(GTK_OBJECT(autoplugger->cache),"caps_proxy",TRUE,NULL);
+
+  // attach signals to the cache
+  gtk_signal_connect (GTK_OBJECT (autoplugger->cache), "first_buffer",
+                      GTK_SIGNAL_FUNC (gst_autoplugger_cache_first_buffer), autoplugger);
+
+  // add the cache to self
+  gst_bin_add (GST_BIN(autoplugger), autoplugger->cache);
+
+  // get the cache's pads so we can attach stuff to them
+  autoplugger->cache_sinkpad = gst_element_get_pad (autoplugger->cache, "sink");
+  autoplugger->cache_srcpad = gst_element_get_pad (autoplugger->cache, "src");
+
+  // attach handlers to the typefind pads
+  gtk_signal_connect (GTK_OBJECT (autoplugger->cache_sinkpad), "caps_changed",
+                      GTK_SIGNAL_FUNC (gst_autoplugger_external_sink_caps_changed), autoplugger);
+  gtk_signal_connect (GTK_OBJECT (autoplugger->cache_srcpad), "caps_changed",
+                      GTK_SIGNAL_FUNC (gst_autoplugger_external_src_caps_changed), autoplugger);
+  gtk_signal_connect (GTK_OBJECT (autoplugger->cache_sinkpad), "caps_nego_failed",
+                      GTK_SIGNAL_FUNC (gst_autoplugger_external_sink_caps_nego_failed), autoplugger);
+  gtk_signal_connect (GTK_OBJECT (autoplugger->cache_srcpad), "caps_nego_failed",
+                      GTK_SIGNAL_FUNC (gst_autoplugger_external_src_caps_nego_failed), autoplugger);
+//  gtk_signal_connect (GTK_OBJECT (autoplugger->cache_sinkpad), "connected",
+//                      GTK_SIGNAL_FUNC (gst_autoplugger_external_sink_connected), autoplugger);
+//  gtk_signal_connect (GTK_OBJECT (autoplugger->cache_srcpad), "connected",
+//                      GTK_SIGNAL_FUNC (gst_autoplugger_external_src_connected), autoplugger);
+
+  // ghost both of these pads to the outside world
+  gst_element_add_ghost_pad (GST_ELEMENT(autoplugger), autoplugger->cache_sinkpad, "sink");
+  gst_element_add_ghost_pad (GST_ELEMENT(autoplugger), autoplugger->cache_srcpad, "src");
+}
+
+
+static void
+gst_autoplugger_external_sink_connected(GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger)
+{
+  GstPadTemplate *peertemplate;
+  GstCaps *peercaps, *peertemplatecaps;
+
+  GST_INFO(GST_CAT_AUTOPLUG, "have cache:sink connected");
+//  autoplugger->sinkpadpeer = peerpad;
+
+  if (autoplugger->sinkpadpeer) {
+    peercaps = GST_PAD_CAPS(autoplugger->sinkpadpeer);
+    if (peercaps)
+      GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer: %s",
+               gst_caps_get_mime(peercaps));
+    peertemplate = GST_PAD_PADTEMPLATE(autoplugger->sinkpadpeer);
+    if (peertemplate) {
+      peertemplatecaps = GST_PADTEMPLATE_CAPS(peertemplate);
+      if (peertemplatecaps) {
+        GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer's padtemplate %s",
+                 gst_caps_get_mime(peertemplatecaps));
+      }
+    }
+  }
+}
+
+static void
+gst_autoplugger_external_src_connected(GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger)
+{
+  GstPadTemplate *peertemplate;
+  GstCaps *peercaps, *peertemplatecaps;
+
+  GST_INFO(GST_CAT_AUTOPLUG, "have cache:src connected");
+//  autoplugger->srcpadpeer = peerpad;
+
+  if (autoplugger->srcpadpeer) {
+    peercaps = GST_PAD_CAPS(autoplugger->srcpadpeer);
+    if (peercaps)
+      GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer: %s",
+               gst_caps_get_mime(peercaps));
+    peertemplate = GST_PAD_PADTEMPLATE(autoplugger->srcpadpeer);
+    if (peertemplate) {
+      peertemplatecaps = GST_PADTEMPLATE_CAPS(peertemplate);
+      if (peertemplatecaps) {
+        GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer's padtemplate %s",
+                 gst_caps_get_mime(peertemplatecaps));
+        autoplugger->sinktemplatecaps = peertemplatecaps;
+//        GST_DEBUG(GST_CAT_AUTOPLUG, "turning on caps nego proxying in cache\n");
+//        gtk_object_set(GTK_OBJECT(autoplugger->cache),"caps_proxy",TRUE,NULL);
+      }
+    }
+  }
+}
+
+
+static void
+gst_autoplugger_external_sink_caps_changed(GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger)
+{
+  GST_INFO(GST_CAT_AUTOPLUG, "have cache:sink caps of %s\n",gst_caps_get_mime(caps));
+  autoplugger->sinkcaps = caps;
+}
+
+static void
+gst_autoplugger_external_src_caps_changed(GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger)
+{
+  GST_INFO(GST_CAT_AUTOPLUG, "have cache:src caps of %s\n",gst_caps_get_mime(caps));
+  autoplugger->srccaps = caps;
+}
+
+
+static gboolean
+gst_autoplugger_autoplug(GstAutoplugger *autoplugger,GstPad *srcpad,GstCaps *srccaps,GstCaps *sinkcaps)
+{
+  GstPad *sinkpad;
+
+  sinkpad = GST_PAD(GST_PAD_PEER(srcpad));
+  GST_DEBUG(GST_CAT_AUTOPLUG,"disconnecting %s:%s and %s:%s to autoplug between them\n",
+            GST_DEBUG_PAD_NAME(srcpad),GST_DEBUG_PAD_NAME(sinkpad));
+  GST_DEBUG(GST_CAT_AUTOPLUG,"srcpadcaps are of type %s\n",gst_caps_get_mime(srccaps));
+  GST_DEBUG(GST_CAT_AUTOPLUG,"sinkpadcaps are of type %s\n",gst_caps_get_mime(sinkcaps));
+
+  // disconnect the pads
+  GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting the pads that will be joined by an autobin\n");
+  gst_pad_disconnect(srcpad,sinkpad);
+
+  if (!autoplugger->autoplug) {
+    autoplugger->autoplug = gst_autoplugfactory_make("static");
+    g_return_val_if_fail(autoplugger->autoplug != NULL, FALSE);
+  }
+  GST_DEBUG(GST_CAT_AUTOPLUG, "building autoplugged bin between caps\n");
+  autoplugger->autobin = gst_autoplug_to_caps(autoplugger->autoplug,
+    srccaps,sinkcaps,NULL);
+  g_return_val_if_fail(autoplugger->autobin != NULL, FALSE);
+  gst_bin_add(GST_BIN(autoplugger),autoplugger->autobin);
+
+gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
+
+  // FIXME this is a hack
+//  GST_DEBUG(GST_CAT_AUTOPLUG, "copying failed caps to srcpad %s:%s to ensure renego\n",GST_DEBUG_PAD_NAME(autoplugger->cache_srcpad));
+//  gst_pad_set_caps(srcpad,srccaps);
+
+  if (GST_PAD_CAPS(srcpad) == NULL) GST_DEBUG(GST_CAT_AUTOPLUG,"no caps on cache:src!\n");
+
+  // attach the autoplugged bin
+  GST_DEBUG(GST_CAT_AUTOPLUG, "attaching the autoplugged bin between the two pads\n");
+  gst_pad_connect(srcpad,gst_element_get_pad(autoplugger->autobin,"sink"));
+gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
+  gst_pad_connect(gst_element_get_pad(autoplugger->autobin,"src_00"),sinkpad);
+gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
+
+  // FIXME try to force the renego
+//  GST_DEBUG(GST_CAT_AUTOPLUG, "trying to force everyone to nego\n");
+//  gst_pad_renegotiate(gst_element_get_pad(autoplugger->autobin,"sink"));
+//  gst_pad_renegotiate(sinkpad);
+
+  return TRUE;
+}
+
+static void
+gst_autoplugger_external_sink_caps_nego_failed(GstPad *pad, gboolean *result, GstAutoplugger *autoplugger)
+{
+  GstPad *srcpad_peer;
+  GstPadTemplate *srcpad_peer_template;
+  GstCaps *srcpad_peer_caps;
+  GstPad *sinkpad_peer;
+  GstCaps *sinkpad_peer_caps;
+
+  GST_INFO(GST_CAT_AUTOPLUG, "have caps nego failure on sinkpad %s:%s!!!",GST_DEBUG_PAD_NAME(pad));
+
+  autoplugger->paused++;
+  if (autoplugger->paused == 1)
+    // try to PAUSE the whole thing
+    gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
+
+  srcpad_peer = GST_PAD(GST_PAD_PEER(autoplugger->cache_srcpad));
+  g_return_if_fail(srcpad_peer != NULL);
+  srcpad_peer_template = GST_PAD_PADTEMPLATE(srcpad_peer);
+  g_return_if_fail(srcpad_peer_template != NULL);
+  srcpad_peer_caps = GST_PADTEMPLATE_CAPS(srcpad_peer_template);
+  g_return_if_fail(srcpad_peer_caps != NULL);
+
+  sinkpad_peer = GST_PAD(GST_PAD_PEER(pad));
+  g_return_if_fail(sinkpad_peer != NULL);
+  sinkpad_peer_caps = GST_PAD_CAPS(sinkpad_peer);
+  g_return_if_fail(sinkpad_peer_caps != NULL);
+
+  if (gst_autoplugger_autoplug(autoplugger,autoplugger->cache_srcpad,sinkpad_peer_caps,srcpad_peer_caps))
+    *result = TRUE;
+
+  // force renego
+  gst_pad_renegotiate(GST_PAD(GST_PAD_PEER(autoplugger->cache_sinkpad)));
+
+  autoplugger->paused--;
+  if (autoplugger->paused == 0)
+    // try to PLAY the whole thing
+    gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
+
+  GST_INFO(GST_CAT_AUTOPLUG, "done dealing with caps nego failure on sinkpad %s:%s",GST_DEBUG_PAD_NAME(pad));
+}
+
+static void
+gst_autoplugger_external_src_caps_nego_failed(GstPad *pad, gboolean *result, GstAutoplugger *autoplugger)
+{
+  GstCaps *srcpad_caps;
+  GstPad *srcpad_peer;
+  GstPadTemplate *srcpad_peer_template;
+  GstCaps *srcpad_peer_caps;
+
+  GST_INFO(GST_CAT_AUTOPLUG, "have caps nego failure on srcpad %s:%s!!!",GST_DEBUG_PAD_NAME(pad));
+
+  autoplugger->paused++;
+  if (autoplugger->paused == 1)
+    // try to PAUSE the whole thing
+    gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
+
+  srcpad_caps = GST_PAD_CAPS(autoplugger->cache_srcpad);
+
+  srcpad_peer = GST_PAD(GST_PAD_PEER(autoplugger->cache_srcpad));
+  g_return_if_fail(srcpad_peer != NULL);
+  srcpad_peer_template = GST_PAD_PADTEMPLATE(srcpad_peer);
+  g_return_if_fail(srcpad_peer_template != NULL);
+  srcpad_peer_caps = GST_PADTEMPLATE_CAPS(srcpad_peer_template);
+  g_return_if_fail(srcpad_peer_caps != NULL);
+
+  if (gst_autoplugger_autoplug(autoplugger,autoplugger->cache_srcpad,srcpad_caps,srcpad_peer_caps))
+    *result = TRUE;
+
+  autoplugger->paused--;
+  if (autoplugger->paused == 0)
+    // try to PLAY the whole thing
+    gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
+
+  autoplugger->disable_nocaps = TRUE;
+
+  GST_INFO(GST_CAT_AUTOPLUG, "done dealing with caps nego failure on srcpad %s:%s",GST_DEBUG_PAD_NAME(pad));
+}
+
+
+static void
+gst_autoplugger_cache_empty(GstElement *element, GstAutoplugger *autoplugger)
+{
+  GstPad *cache_sinkpad_peer,*cache_srcpad_peer;
+
+  GST_INFO(GST_CAT_AUTOPLUG, "autoplugger cache has hit empty, we can now remove it");
+
+  autoplugger->paused++;
+  if (autoplugger->paused == 1)
+    // try to PAUSE the whole thing
+    gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
+
+  // disconnect the cache from its peers
+  GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting autoplugcache from its peers\n");
+  cache_sinkpad_peer = GST_PAD (GST_PAD_PEER(autoplugger->cache_sinkpad));
+  cache_srcpad_peer = GST_PAD (GST_PAD_PEER(autoplugger->cache_srcpad));
+  gst_pad_disconnect(cache_sinkpad_peer,autoplugger->cache_sinkpad);
+  gst_pad_disconnect(autoplugger->cache_srcpad,cache_srcpad_peer);
+
+  // remove the cache from self
+  GST_DEBUG(GST_CAT_AUTOPLUG, "removing the cache from the autoplugger\n");
+  gst_bin_remove (GST_BIN(autoplugger), autoplugger->cache);
+
+  // connect the two pads
+  GST_DEBUG(GST_CAT_AUTOPLUG, "reconnecting the autoplugcache's former peers\n");
+  gst_pad_connect(cache_sinkpad_peer,cache_srcpad_peer);
+
+  autoplugger->paused--;
+  if (autoplugger->paused == 0)
+    // try to PLAY the whole thing
+    gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
+
+  xmlSaveFile("autoplugger.gst", gst_xml_write(GST_ELEMENT_SCHED(autoplugger)->parent));
+
+  GST_INFO(GST_CAT_AUTOPLUG, "autoplugger_cache_empty finished");
+}
+
+static void
+gst_autoplugger_typefind_have_type(GstElement *element, GstCaps *caps, GstAutoplugger *autoplugger) 
+{
+  GST_INFO(GST_CAT_AUTOPLUG, "typefind claims to have a type: %s",gst_caps_get_mime(caps));
+
+gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
+
+  autoplugger->paused++;
+  if (autoplugger->paused == 1)
+    // try to PAUSE the whole thing
+    gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
+
+  // first disconnect the typefind and shut it down
+  GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting typefind from the cache\n");
+  gst_pad_disconnect(autoplugger->cache_srcpad,autoplugger->typefind_sinkpad);
+  gst_bin_remove(GST_BIN(autoplugger),autoplugger->typefind);
+
+  // FIXME FIXME now we'd compare caps and see if we need to autoplug something in the middle, but for 
+  // now we're going to just reconnect where we left off
+  // FIXME FIXME FIXME!!!: this should really be done in the caps failure!!!
+/*
+  if (!autoplugger->autoplug) {
+    autoplugger->autoplug = gst_autoplugfactory_make("static");
+  }
+  autoplugger->autobin = gst_autoplug_to_caps(autoplugger->autoplug,
+      caps,autoplugger->sinktemplatecaps,NULL);
+  g_return_if_fail(autoplugger->autobin != NULL);
+  gst_bin_add(GST_BIN(autoplugger),autoplugger->autobin);
+
+//  // re-attach the srcpad's original peer to the cache
+//  GST_DEBUG(GST_CAT_AUTOPLUG, "reconnecting the cache to the downstream peer\n");
+//  gst_pad_connect(autoplugger->cache_srcpad,autoplugger->srcpadpeer);
+
+  // attach the autoplugged bin
+  GST_DEBUG(GST_CAT_AUTOPLUG, "attaching the autoplugged bin between cache and downstream peer\n");
+  gst_pad_connect(autoplugger->cache_srcpad,gst_element_get_pad(autoplugger->autobin,"sink"));
+  gst_pad_connect(gst_element_get_pad(autoplugger->autobin,"src_00"),autoplugger->srcpadpeer);
+*/
+
+  // FIXME set the caps on the new connection
+//  GST_DEBUG(GST_CAT_AUTOPLUG,"forcing caps on the typefound pad\n");
+//  gst_pad_set_caps(autoplugger->cache_srcpad,caps);
+
+  // reattach the original outside srcpad
+  GST_DEBUG(GST_CAT_AUTOPLUG,"re-attaching downstream peer to autoplugcache\n");
+  gst_pad_connect(autoplugger->cache_srcpad,autoplugger->srcpadpeer);
+
+  // now reset the autoplugcache
+  GST_DEBUG(GST_CAT_AUTOPLUG, "resetting the cache to send first buffer(s) again\n");
+  gtk_object_set(GTK_OBJECT(autoplugger->cache),"reset",TRUE,NULL);
+
+  // attach the cache_empty handler
+  // FIXME this is the wrong place, it shouldn't be done until we get successful caps nego!
+  gtk_signal_connect(GTK_OBJECT(autoplugger->cache),"cache_empty",
+                     GTK_SIGNAL_FUNC(gst_autoplugger_cache_empty),autoplugger);
+
+  autoplugger->paused--;
+  if (autoplugger->paused == 0)
+    // try to PLAY the whole thing
+    gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
+
+  GST_INFO(GST_CAT_AUTOPLUG, "typefind_have_type finished");
+gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
+}
+
+static void
+gst_autoplugger_cache_first_buffer(GstElement *element,GstBuffer *buf,GstAutoplugger *autoplugger)
+{
+  GST_INFO(GST_CAT_AUTOPLUG, "have first buffer through cache");
+  autoplugger->cache_first_buffer = TRUE;
+
+  // if there are no established caps, worry
+  if (!autoplugger->sinkcaps) {
+    GST_INFO(GST_CAT_AUTOPLUG, "have no caps for the buffer, Danger Will Robinson!");
+
+if (autoplugger->disable_nocaps) {
+  GST_DEBUG(GST_CAT_AUTOPLUG, "not dealing with lack of caps this time\n");
+  return;
+}
+
+gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
+
+  autoplugger->paused++;
+  if (autoplugger->paused == 1)
+    // try to PAUSE the whole thing
+    gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
+
+    // detach the srcpad
+    GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting cache from its downstream peer\n");
+    autoplugger->srcpadpeer = GST_PAD(GST_PAD_PEER(autoplugger->cache_srcpad));
+    gst_pad_disconnect(autoplugger->cache_srcpad,autoplugger->srcpadpeer);
+
+    // instantiate the typefind and set up the signal handlers
+    if (!autoplugger->typefind) {
+      GST_DEBUG(GST_CAT_AUTOPLUG, "creating typefind and setting signal handler\n");
+      autoplugger->typefind = gst_elementfactory_make("typefind","unnamed_typefind");
+      autoplugger->typefind_sinkpad = gst_element_get_pad(autoplugger->typefind,"sink");
+      gtk_signal_connect(GTK_OBJECT(autoplugger->typefind),"have_type",
+                         GTK_SIGNAL_FUNC (gst_autoplugger_typefind_have_type), autoplugger);
+    }
+    // add it to self and attach it
+    GST_DEBUG(GST_CAT_AUTOPLUG, "adding typefind to self and connecting to cache\n");
+    gst_bin_add(GST_BIN(autoplugger),autoplugger->typefind);
+    gst_pad_connect(autoplugger->cache_srcpad,autoplugger->typefind_sinkpad);
+
+    // bring the typefind into playing state
+    GST_DEBUG(GST_CAT_AUTOPLUG, "setting typefind state to PLAYING\n");
+    gst_element_set_state(autoplugger->cache,GST_STATE_PLAYING);
+
+  autoplugger->paused--;
+  if (autoplugger->paused == 0)
+    // try to PLAY the whole thing
+    gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
+
+    GST_INFO(GST_CAT_AUTOPLUG,"here we go into nothingness, hoping the typefind will return us to safety");
+gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
+  } else {
+//    // attach the cache_empty handler, since the cache simply isn't needed
+//    gtk_signal_connect(GTK_OBJECT(autoplugger->cache),"cache_empty",
+//                       GTK_SIGNAL_FUNC(gst_autoplugger_cache_empty),autoplugger);  
+  }
+}
+
+static void
+gst_autoplugger_set_arg (GtkObject *object, GtkArg *arg, guint id)
+{
+  GstAutoplugger *autoplugger;
+
+  autoplugger = GST_AUTOPLUGGER (object);
+
+  switch (id) {
+    default:
+      break;
+  }
+}
+
+static void
+gst_autoplugger_get_arg (GtkObject *object, GtkArg *arg, guint id)
+{
+  GstAutoplugger *autoplugger;
+
+  autoplugger = GST_AUTOPLUGGER (object);
+
+  switch (id) {
+    default:
+      arg->type = GTK_TYPE_INVALID;
+      break;
+  }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+  GstElementFactory *factory;
+
+  factory = gst_elementfactory_new ("autoplugger", GST_TYPE_AUTOPLUGGER,
+                                    &gst_autoplugger_details);
+  g_return_val_if_fail (factory != NULL, FALSE);
+
+  gst_plugin_add_factory (plugin, factory);
+
+  return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+  GST_VERSION_MAJOR,
+  GST_VERSION_MINOR,
+  "autoplugger",
+  plugin_init
+};
+
index 11403a0..3edf83e 100644 (file)
@@ -124,7 +124,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
        if (gst_caps_check_compatibility (gst_padtemplate_get_caps (srctemp), 
                                gst_padtemplate_get_caps (desttemp))) {
          GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
-                         "factory \"%s\" can connect with factory \"%s\"", src->name, dest->name);
+                         "factory \"%s\" can connect with factory \"%s\"\n", src->name, dest->name);
           return TRUE;
        }
       }
@@ -134,7 +134,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
     srctemps = g_list_next (srctemps);
   }
   GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
-                 "factory \"%s\" cannot connect with factory \"%s\"", src->name, dest->name);
+                 "factory \"%s\" cannot connect with factory \"%s\"\n", src->name, dest->name);
   return FALSE;
 }
 
index c544f7f..cbfc798 100644 (file)
@@ -123,7 +123,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
           desttemp->direction == GST_PAD_SINK) {
        if (gst_caps_check_compatibility (GST_PADTEMPLATE_CAPS (srctemp), GST_PADTEMPLATE_CAPS (desttemp))) {
          GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
-                         "factory \"%s\" can connect with factory \"%s\"", src->name, dest->name);
+                         "factory \"%s\" can connect with factory \"%s\"\n", src->name, dest->name);
           return TRUE;
        }
       }
@@ -133,7 +133,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
     srctemps = g_list_next (srctemps);
   }
   GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
-                 "factory \"%s\" cannot connect with factory \"%s\"", src->name, dest->name);
+                 "factory \"%s\" cannot connect with factory \"%s\"\n", src->name, dest->name);
   return FALSE;
 }
 
@@ -154,12 +154,21 @@ gst_autoplug_pads_autoplug_func (GstElement *src, GstPad *pad, GstElement *sink)
     if (gst_pad_get_direction(sinkpad) == GST_PAD_SINK &&
         !GST_PAD_CONNECTED (pad) && !GST_PAD_CONNECTED(sinkpad))
     {
+      GstElementState state = GST_STATE (gst_element_get_parent (src));
+
+      if (state == GST_STATE_PLAYING)
+        gst_element_set_state (GST_ELEMENT (gst_element_get_parent (src)), GST_STATE_PAUSED);
+       
       if ((connected = gst_pad_connect (pad, sinkpad))) {
+        if (state == GST_STATE_PLAYING)
+          gst_element_set_state (GST_ELEMENT (gst_element_get_parent (src)), GST_STATE_PLAYING);
        break;
       }
       else {
         GST_DEBUG (0,"pads incompatible %s, %s\n", GST_PAD_NAME (pad), GST_PAD_NAME (sinkpad));
       }
+      if (state == GST_STATE_PLAYING)
+        gst_element_set_state (GST_ELEMENT (gst_element_get_parent (src)), GST_STATE_PLAYING);
     }
     sinkpads = g_list_next(sinkpads);
   }
@@ -423,12 +432,13 @@ differ:
        // create a new queue and add to the previous bin
         queue = gst_elementfactory_make("queue", g_strconcat("queue_", GST_ELEMENT_NAME(element), NULL));
         GST_DEBUG (0,"adding element \"%s\"\n", GST_ELEMENT_NAME (element));
-        gst_bin_add(GST_BIN(thebin), queue);
-        gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (queue));
 
        // this will be the new bin for all following elements
         thebin = gst_elementfactory_make("thread", g_strconcat("thread_", GST_ELEMENT_NAME(element), NULL));
 
+        gst_bin_add(GST_BIN(thebin), queue);
+        gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (queue));
+
         srcpad = gst_element_get_pad(queue, "src");
 
         gst_autoplug_pads_autoplug(thesrcelement, queue);
index 2de2b3e..478dba0 100644 (file)
@@ -67,6 +67,11 @@ cothread_init (void)
 {
   cothread_context *ctx = (cothread_context *)malloc(sizeof(cothread_context));
 
+  // we consider the initiating process to be cothread 0
+  ctx->nthreads = 1;
+  ctx->current = 0;
+  ctx->data = g_hash_table_new(g_str_hash, g_str_equal);
+
   GST_INFO (GST_CAT_COTHREADS,"initializing cothreads");
 
   if (_cothread_key == -1) {
@@ -89,12 +94,14 @@ cothread_init (void)
   ctx->threads[0]->sp = (void *)CURRENT_STACK_FRAME;
   ctx->threads[0]->pc = 0;
 
-  GST_INFO (GST_CAT_COTHREADS,"0th thread is %p at sp:%p",ctx->threads[0], ctx->threads[0]->sp);
+  // initialize the lock
+#ifdef COTHREAD_ATOMIC
+  atomic_set (&ctx->threads[0]->lock, 0);
+#else
+  ctx->threads[0]->lock = g_mutex_new();
+#endif
 
-  // we consider the initiating process to be cothread 0
-  ctx->nthreads = 1;
-  ctx->current = 0;
-  ctx->data = g_hash_table_new(g_str_hash, g_str_equal);
+  GST_INFO (GST_CAT_COTHREADS,"0th thread is %p at sp:%p",ctx->threads[0], ctx->threads[0]->sp);
 
   return ctx;
 }
@@ -118,7 +125,7 @@ cothread_create (cothread_context *ctx)
   }
   GST_DEBUG (0,"pthread_self() %ld\n",pthread_self());
   //if (0) {
-  if (pthread_self() == 0) {
+  if (pthread_self() == 0) {   // FIXME uh, what does this test really do?
     s = (cothread_state *)malloc(COTHREAD_STACKSIZE);
     GST_DEBUG (0,"new stack (case 1) at %p\n",s);
   } else {
@@ -145,6 +152,13 @@ cothread_create (cothread_context *ctx)
   // is this needed anymore?
   s->top_sp = s->sp;
 
+  // initialize the lock
+#ifdef COTHREAD_ATOMIC
+  atomic_set (s->lock, 0);
+#else
+  s->lock = g_mutex_new();
+#endif
+
   GST_INFO (GST_CAT_COTHREADS,"created cothread #%d: %p at sp:%p", ctx->nthreads, s, s->sp);
 
   ctx->threads[ctx->nthreads++] = s;
@@ -186,6 +200,18 @@ cothread_main(cothread_context *ctx)
   return ctx->threads[0];
 }
 
+/**
+ * cothread_current)main:
+ *
+ * Returns: the #cothread_state of the main (0th) thread in the current pthread
+ */
+cothread_state*
+cothread_current_main(void)
+{
+  cothread_context *ctx = pthread_getspecific(_cothread_key);
+  return ctx->threads[0];
+}
+
 static void 
 cothread_stub (void) 
 {
@@ -195,6 +221,11 @@ cothread_stub (void)
   GST_DEBUG_ENTER("");
 
   thread->flags |= COTHREAD_STARTED;
+//#ifdef COTHREAD_ATOMIC
+//  // do something here to lock
+//#else
+//  g_mutex_lock(thread->lock);
+//#endif
   while (1) {
     thread->func(thread->argc,thread->argv);
     // we do this to avoid ever returning, we just switch to 0th thread
@@ -281,8 +312,22 @@ cothread_switch (cothread_state *thread)
 #endif
   if (current == thread) goto selfswitch;
 
+  // unlock the current thread, we're out of that context now
+#ifdef COTHREAD_ATOMIC
+  // do something to unlock the cothread
+#else
+  g_mutex_unlock(current->lock);
+#endif
+
+  // lock the next cothread before we even switch to it
+#ifdef COTHREAD_ATOMIC
+  // do something to lock the cothread
+#else
+  g_mutex_lock(thread->lock);
+#endif
+
   // find the number of the thread to switch to
-  GST_INFO (GST_CAT_COTHREAD_SWITCH,"switching from cothread %d to to cothread #%d",
+  GST_INFO (GST_CAT_COTHREAD_SWITCH,"switching from cothread #%d to cothread #%d",
             ctx->current,thread->threadnum);
   ctx->current = thread->threadnum;
 
@@ -319,7 +364,7 @@ cothread_switch (cothread_state *thread)
 
 #ifdef COTHREAD_PARANOID
 nothread:
-  g_print("cothread: there's no thread, strange...\n");
+  g_print("cothread: can't switch to NULL cothread!\n");
   return;
 nocontext:
   g_print("cothread: there's no context, help!\n");
@@ -332,3 +377,35 @@ selfswitch:
   g_print("cothread: trying to switch to same thread, legal but not necessary\n");
   return;
 }
+
+
+void
+cothread_lock (cothread_state *thread)
+{
+#ifdef COTHREAD_ATOMIC
+  // do something to lock the cothread
+#else
+  g_mutex_lock(thread->lock);
+#endif
+}
+
+gboolean
+cothread_trylock (cothread_state *thread)
+{
+#ifdef COTHREAD_ATOMIC
+  // do something to try to lock the cothread
+#else
+  return g_mutex_trylock(thread->lock);
+#endif
+}
+
+void
+cothread_unlock (cothread_state *thread)
+{
+#ifdef COTHREAD_ATOMIC
+  // do something to unlock the cothread
+#else
+  g_mutex_unlock(thread->lock);
+#endif
+}
+
index d48b1ab..d95d7cf 100644 (file)
 #include <glib.h>
 #include <setjmp.h>
 
+#ifdef HAVE_ATOMIC_H
+#include <asm/atomic.h>
+#endif
+
+#undef COTHREAD_ATOMIC
+
 #ifndef CURRENT_STACK_FRAME
 #define CURRENT_STACK_FRAME  ({ char __csf; &__csf; })
 #endif /* CURRENT_STACK_FRAME */
@@ -47,10 +53,16 @@ struct _cothread_state {
 
   int flags;
   void *sp;
+  jmp_buf jmp;
   /* is this needed any more? */
   void *top_sp;
   void *pc;
-  jmp_buf jmp;
+
+#ifdef COTHREAD_ATOMIC
+  atomic_t lock;
+#else
+  GMutex *lock;
+#endif
 };
 
 
@@ -63,6 +75,11 @@ void                         cothread_switch         (cothread_state *thread);
 void                           cothread_set_data       (cothread_state *thread, gchar *key, gpointer data);
 gpointer                       cothread_get_data       (cothread_state *thread, gchar *key);
 
+void                           cothread_lock           (cothread_state *thread);
+gboolean                       cothread_trylock        (cothread_state *thread);
+void                           cothread_unlock         (cothread_state *thread);
+
 cothread_state*                        cothread_main           (cothread_context *ctx);
+cothread_state*                        cothread_current_main   (void);
 
 #endif /* __COTHREAD_H__ */
index 5fa6af2..97570bb 100644 (file)
@@ -49,6 +49,7 @@ enum {
   ARG_OUTPUT,
   ARG_PATTERN,
   ARG_NUM_BUFFERS,
+  ARG_EOS,
   ARG_SILENT
 };
 
@@ -125,6 +126,8 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
                            GTK_ARG_READWRITE, ARG_PATTERN);
   gtk_object_add_arg_type ("GstFakeSrc::num_buffers", GTK_TYPE_INT,
                            GTK_ARG_READWRITE, ARG_NUM_BUFFERS);
+  gtk_object_add_arg_type ("GstFakeSrc::eos", GTK_TYPE_BOOL,
+                           GTK_ARG_READWRITE, ARG_EOS);
   gtk_object_add_arg_type ("GstFakeSrc::silent", GTK_TYPE_BOOL,
                            GTK_ARG_READWRITE, ARG_SILENT);
 
@@ -222,6 +225,10 @@ gst_fakesrc_set_arg (GtkObject *object, GtkArg *arg, guint id)
     case ARG_NUM_BUFFERS:
       src->num_buffers = GTK_VALUE_INT (*arg);
       break;
+    case ARG_EOS:
+      src->eos = GTK_VALUE_BOOL (*arg);
+GST_INFO (0, "will EOS on next buffer");
+      break;
     case ARG_SILENT:
       src->silent = GTK_VALUE_BOOL (*arg);
       break;
@@ -256,6 +263,8 @@ gst_fakesrc_get_arg (GtkObject *object, GtkArg *arg, guint id)
     case ARG_NUM_BUFFERS:
       GTK_VALUE_INT (*arg) = src->num_buffers;
       break;
+    case ARG_EOS:
+      GTK_VALUE_BOOL (*arg) = src->eos;
     case ARG_SILENT:
       GTK_VALUE_BOOL (*arg) = src->silent;
       break;
@@ -295,6 +304,12 @@ gst_fakesrc_get(GstPad *pad)
       src->num_buffers--;
   }
 
+  if (src->eos) {
+    GST_INFO (0, "fakesrc is setting eos on pad");
+    gst_pad_set_eos (pad);
+    return NULL;
+  }
+
   if (!src->silent)
     g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad));
   buf = gst_buffer_new();
@@ -336,7 +351,13 @@ gst_fakesrc_loop(GstElement *element)
       }
       else {
       if (src->num_buffers > 0)
-        src->num_buffers--;
+         src->num_buffers--;
+      }
+
+      if (src->eos) {
+        GST_INFO (0, "fakesrc is setting eos on pad");
+        gst_pad_set_eos (pad);
+        return;
       }
 
       buf = gst_buffer_new();
index a795c19..ba92f63 100644 (file)
@@ -65,6 +65,7 @@ struct _GstFakeSrc {
   GstElement element;
 
   gboolean loop_based;
+  gboolean eos;
   gint numsrcpads;
   GSList *srcpads;
   GstFakeSrcOutputType output;
index 8cddd5d..6a00e1e 100644 (file)
@@ -407,4 +407,4 @@ gst_sinesrc_factory_init (GstElementFactory *factory)
   gst_elementfactory_add_padtemplate (factory, src_temp);
   
   return TRUE;
-}
\ No newline at end of file
+}
index be7eeb4..e859b04 100644 (file)
--- a/gst/gst.c
+++ b/gst/gst.c
@@ -174,21 +174,6 @@ gst_init_check (int     *argc,
 
        (*argv)[i] = NULL;
       }
-      else if (!strncmp ("--gst-mask=", (*argv)[i], 11)) {
-       guint32 val;
-
-        // handle either 0xHEX or dec
-        if (*((*argv)[i]+12) == 'x') {
-          sscanf ((*argv)[i]+13, "%08x", &val);
-        } else {
-          sscanf ((*argv)[i]+11, "%d", &val);
-        }
-
-       gst_debug_set_categories (val);
-       gst_info_set_categories (val);
-
-       (*argv)[i] = NULL;
-      }
       else if (!strncmp ("--gst-plugin-spew", (*argv)[i], 17)) {
         _gst_plugin_spew = TRUE;
 
@@ -247,10 +232,19 @@ gst_init_check (int     *argc,
     g_print ("--------------------------------------------------------\n");
 
     for (i = 0; i<GST_CAT_MAX_CATEGORY; i++) {
-      g_print ("   0x%08x     %s%s     %s\n", 1<<i, 
-                  (gst_info_get_categories() & (1<<i)?"(enabled)":"         "),
-                  (gst_debug_get_categories() & (1<<i)?"/(enabled)":"/         "),
-                  gst_get_category_name (i));
+      if (gst_get_category_name(i)) {
+#if GST_DEBUG_COLOR
+        g_print ("   0x%08x     %s%s     \033[%sm%s\033[00m\n", 1<<i, 
+                 (gst_info_get_categories() & (1<<i)?"(enabled)":"         "),
+                 (gst_debug_get_categories() & (1<<i)?"/(enabled)":"/         "),
+                 _gst_category_colors[i], gst_get_category_name (i));
+#else
+        g_print ("   0x%08x     %s%s     %s\n", 1<<i, 
+                 (gst_info_get_categories() & (1<<i)?"(enabled)":"         "),
+                 (gst_debug_get_categories() & (1<<i)?"/(enabled)":"/         "),
+                 gst_get_category_name (i));
+#endif
+      }
     }
 
     ret = FALSE;
index 94a1444..73bdb0b 100644 (file)
--- a/gst/gst.h
+++ b/gst/gst.h
@@ -27,6 +27,7 @@
 #include <glib.h>
 
 #include <gst/gstversion.h>
+#include <gst/gsttypes.h>
 
 #include <gst/gstinfo.h>
 #include <gst/gstobject.h>
@@ -48,6 +49,7 @@
 #include <gst/gsttrace.h>
 #include <gst/gstxml.h>
 #include <gst/cothreads.h>
+#include <gst/gstscheduler.h>
 
 #include <gst/gstparse.h>
 
index dc0331e..a45f134 100644 (file)
@@ -46,7 +46,6 @@ static gboolean                       gst_bin_change_state_type       (GstBin *bin,
                                                                 GstElementState state,
                                                                 GtkType type);
 
-static void                    gst_bin_create_plan_func        (GstBin *bin);
 static gboolean                        gst_bin_iterate_func            (GstBin *bin);
 
 static xmlNodePtr              gst_bin_save_thyself            (GstObject *object, xmlNodePtr parent);
@@ -113,8 +112,6 @@ gst_bin_class_init (GstBinClass *klass)
   gtk_object_class_add_signals (gtkobject_class, gst_bin_signals, LAST_SIGNAL);
 
   klass->change_state_type =           gst_bin_change_state_type;
-  klass->create_plan =                 gst_bin_create_plan_func;
-  klass->schedule =                    gst_bin_schedule_func;
   klass->iterate =                     gst_bin_iterate_func;
 
   gstobject_class->save_thyself =      gst_bin_save_thyself;
@@ -155,6 +152,105 @@ gst_bin_new (const gchar *name)
   return gst_elementfactory_make ("bin", name);
 }
 
+static inline void
+gst_bin_reset_element_sched (GstElement *element, GstSchedule *sched)
+{
+  GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "resetting element's scheduler");
+
+  // first remove the element from its current schedule, if any
+//  if (GST_ELEMENT_SCHED(element))
+//    GST_SCHEDULE_REMOVE_ELEMENT (GST_ELEMENT_SCHED(element), element);
+  // then set the new manager
+  gst_element_set_sched (element,sched);
+
+  // and add it to the new scheduler
+//  if (sched)
+//    GST_SCHEDULE_ADD_ELEMENT (sched, element);
+}
+
+void
+gst_bin_set_element_sched (GstElement *element,GstSchedule *sched)
+{
+  GList *children;
+  GstElement *child;
+
+  g_return_if_fail (element != NULL);
+  g_return_if_fail (GST_IS_ELEMENT(element));
+  g_return_if_fail (sched != NULL);
+  g_return_if_fail (GST_IS_SCHEDULE(sched));
+
+  GST_INFO (GST_CAT_SCHEDULING, "setting element \"%s\" sched to %p",GST_ELEMENT_NAME(element),
+            sched);
+
+  // if it's actually a Bin
+  if (GST_IS_BIN(element)) {
+
+    if (GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
+      GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not resetting");
+      return;
+    }
+
+    GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting children's schedule to parent's");
+    GST_SCHEDULE_ADD_ELEMENT (sched, element);
+
+    // set the children's schedule
+    children = GST_BIN(element)->children;
+    while (children) {
+      child = GST_ELEMENT (children->data);
+      children = g_list_next(children);
+
+      gst_bin_set_element_sched (child, sched);
+    }
+
+  // otherwise, if it's just a regular old element
+  } else {
+    GST_SCHEDULE_ADD_ELEMENT (sched, element);
+  }
+}
+
+
+void
+gst_bin_unset_element_sched (GstElement *element)
+{
+  GList *children;
+  GstElement *child;
+
+  g_return_if_fail (element != NULL);
+  g_return_if_fail (GST_IS_ELEMENT(element));
+
+  GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from it sched %p",
+            GST_ELEMENT_NAME(element),GST_ELEMENT_SCHED(element));
+
+  // if it's actually a Bin
+  if (GST_IS_BIN(element)) {
+
+    if (GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
+      GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not unsetting sched");
+      return;
+    }
+
+    // FIXME this check should be irrelevant
+    if (GST_ELEMENT_SCHED (element))
+      GST_SCHEDULE_REMOVE_ELEMENT (GST_ELEMENT_SCHED(element), element);
+
+    // for each child, remove them from their schedule
+    children = GST_BIN(element)->children;
+    while (children) {
+      child = GST_ELEMENT (children->data);
+      children = g_list_next(children);
+
+      gst_bin_unset_element_sched (child);
+    }
+
+  // otherwise, if it's just a regular old element
+  } else {
+    // FIXME this check should be irrelevant
+    if (GST_ELEMENT_SCHED (element))
+      GST_SCHEDULE_REMOVE_ELEMENT (GST_ELEMENT_SCHED(element), element);
+  }
+}
+
+
 /**
  * gst_bin_add:
  * @bin: #GstBin to add element to
@@ -172,19 +268,30 @@ gst_bin_add (GstBin *bin,
   g_return_if_fail (element != NULL);
   g_return_if_fail (GST_IS_ELEMENT (element));
 
-  // must be NULL or PAUSED state in order to modify bin
-  g_return_if_fail ((GST_STATE (bin) == GST_STATE_NULL) ||
-                   (GST_STATE (bin) == GST_STATE_PAUSED));
+  GST_DEBUG (GST_CAT_PARENTAGE, "adding element \"%s\" to bin \"%s\"\n",
+             GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(bin));
+
+  // must be not be in PLAYING state in order to modify bin
+//  g_return_if_fail (GST_STATE (bin) != GST_STATE_PLAYING);
+
+  // the element must not already have a parent
+  g_return_if_fail (GST_ELEMENT_PARENT(element) == NULL);
+
+  // then check to see if the element's name is already taken in the bin
+  g_return_if_fail (gst_object_check_uniqueness (bin->children, GST_ELEMENT_NAME(element)) == TRUE);
 
+  // set the element's parent and add the element to the bin's list of children
+  gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
   bin->children = g_list_append (bin->children, element);
   bin->numchildren++;
-  gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
 
-  GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child %s", GST_ELEMENT_NAME (element));
+  ///// now we have to deal with manager stuff
+  // we can only do this if there's a scheduler:
+  // if we're not a manager, and aren't attached to anything, we have no sched (yet)
+  if (GST_ELEMENT_SCHED(bin) != NULL)
+    gst_bin_set_element_sched (element, GST_ELEMENT_SCHED(bin));
 
-  /* we know we have at least one child, we just added one... */
-//  if (GST_STATE(element) < GST_STATE_READY)
-//    gst_bin_change_state_norecurse(bin,GST_STATE_READY);
+  GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child \"%s\"", GST_ELEMENT_NAME (element));
 
   gtk_signal_emit (GTK_OBJECT (bin), gst_bin_signals[OBJECT_ADDED], element);
 }
@@ -206,24 +313,32 @@ gst_bin_remove (GstBin *bin,
   g_return_if_fail (GST_IS_ELEMENT (element));
   g_return_if_fail (bin->children != NULL);
 
-  // must be NULL or PAUSED state in order to modify bin
-  g_return_if_fail ((GST_STATE (bin) == GST_STATE_NULL) ||
-                   (GST_STATE (bin) == GST_STATE_PAUSED));
+  // must not be in PLAYING state in order to modify bin
+  g_return_if_fail (GST_STATE (bin) != GST_STATE_PLAYING);
 
+  // the element must have its parent set to the current bin
+  g_return_if_fail (GST_ELEMENT_PARENT(element) == (GstObject *)bin);
+
+  // the element must be in the bin's list of children
   if (g_list_find(bin->children, element) == NULL) {
     // FIXME this should be a warning!!!
     GST_ERROR_OBJECT(bin,element,"no such element in bin");
     return;
   }
 
-  gst_object_unparent (GST_OBJECT (element));
+  // remove this element from the list of managed elements
+  gst_bin_unset_element_sched (element);
+
+  // now remove the element from the list of elements
   bin->children = g_list_remove (bin->children, element);
   bin->numchildren--;
 
   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "removed child %s", GST_ELEMENT_NAME (element));
 
+  gst_object_unparent (GST_OBJECT (element));
+
   /* if we're down to zero children, force state to NULL */
-  if (bin->numchildren == 0)
+  if (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL)
     gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
 }
 
@@ -236,62 +351,47 @@ gst_bin_change_state (GstElement *element)
   GstElement *child;
   GstElementStateReturn ret;
 
-  GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME  (element));
+//  GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME  (element));
 
   g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
 
   bin = GST_BIN (element);
 
-//  GST_DEBUG (0,"currently %d(%s), %d(%s) pending\n",GST_STATE (element),
-//          _gst_print_statename (GST_STATE (element)), GST_STATE_PENDING (element),
-//          _gst_print_statename (GST_STATE_PENDING (element)));
+//  GST_DEBUG (GST_CAT_STATES,"currently %d(%s), %d(%s) pending\n",GST_STATE (element),
+//          gst_element_statename (GST_STATE (element)), GST_STATE_PENDING (element),
+//          gst_element_statename (GST_STATE_PENDING (element)));
 
-  GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing bin's state from %s to %s",
-                _gst_print_statename (GST_STATE (element)),
-                _gst_print_statename (GST_STATE_PENDING (element)));
+  GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing childrens' state from %s to %s",
+                gst_element_statename (GST_STATE (element)),
+                gst_element_statename (GST_STATE_PENDING (element)));
 
 //  g_return_val_if_fail(bin->numchildren != 0, GST_STATE_FAILURE);
 
-  switch (GST_STATE_TRANSITION (element)) {
-    case GST_STATE_NULL_TO_READY:
-    {
-      GstObject *parent;
-
-      parent = gst_object_get_parent (GST_OBJECT (element));
-
-      if (!parent || !GST_IS_BIN (parent))
-        gst_bin_create_plan (bin);
-      else
-        GST_DEBUG (0,"not creating plan for '%s'\n",GST_ELEMENT_NAME  (bin));
-
-      break;
-    }
-    case GST_STATE_READY_TO_NULL:
-      GST_FLAG_UNSET (bin, GST_BIN_FLAG_MANAGER);
-    default:
-      break;
-  }
 
 //  g_print("-->\n");
   children = bin->children;
   while (children) {
     child = GST_ELEMENT (children->data);
-    GST_DEBUG (0,"setting state on '%s'\n",GST_ELEMENT_NAME  (child));
+//    GST_DEBUG (GST_CAT_STATES,"setting state on '%s'\n",GST_ELEMENT_NAME  (child));
     switch (gst_element_set_state (child, GST_STATE_PENDING (element))) {
       case GST_STATE_FAILURE:
         GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING;
-        GST_DEBUG (0,"child '%s' failed to go to state %d(%s)\n", GST_ELEMENT_NAME  (child),
-              GST_STATE_PENDING (element), _gst_print_statename (GST_STATE_PENDING (element)));
+        GST_DEBUG (GST_CAT_STATES,"child '%s' failed to go to state %d(%s)\n", GST_ELEMENT_NAME (child),
+              GST_STATE_PENDING (element), gst_element_statename (GST_STATE_PENDING (element)));
         return GST_STATE_FAILURE;
         break;
       case GST_STATE_ASYNC:
-        GST_DEBUG (0,"child '%s' is changing state asynchronously\n", GST_ELEMENT_NAME  (child));
+        GST_DEBUG (GST_CAT_STATES,"child '%s' is changing state asynchronously\n", GST_ELEMENT_NAME (child));
         break;
     }
 //    g_print("\n");
     children = g_list_next (children);
   }
-//  g_print("<-- \"%s\"\n",gst_object_get_name(GST_OBJECT(bin)));
+//  g_print("<-- \"%s\"\n",GST_OBJECT_NAME(bin));
+
+  GST_INFO_ELEMENT (GST_CAT_STATES, element, "done changing bin's state from %s to %s",
+                gst_element_statename (GST_STATE (element)),
+                gst_element_statename (GST_STATE_PENDING (element)));
   ret =  gst_bin_change_state_norecurse (bin);
 
   return ret;
@@ -301,10 +401,10 @@ gst_bin_change_state (GstElement *element)
 static GstElementStateReturn
 gst_bin_change_state_norecurse (GstBin *bin)
 {
-
-  if (GST_ELEMENT_CLASS (parent_class)->change_state)
+  if (GST_ELEMENT_CLASS (parent_class)->change_state) {
+    GST_DEBUG_ELEMENT (GST_CAT_STATES, bin, "setting bin's own state\n");
     return GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (bin));
-  else
+  else
     return GST_STATE_FAILURE;
 }
 
@@ -317,7 +417,7 @@ gst_bin_change_state_type(GstBin *bin,
   GstElement *child;
 
 //  g_print("gst_bin_change_state_type(\"%s\",%d,%d);\n",
-//          gst_object_get_name(GST_OBJECT(bin)),state,type);
+//          GST_OBJECT_NAME(bin))),state,type);
 
   g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
   g_return_val_if_fail (bin->numchildren != 0, FALSE);
@@ -359,7 +459,7 @@ gst_bin_set_state_type (GstBin *bin,
 {
   GstBinClass *oclass;
 
-  GST_DEBUG (0,"gst_bin_set_state_type(\"%s\",%d,%d)\n",
+  GST_DEBUG (GST_CAT_STATES,"gst_bin_set_state_type(\"%s\",%d,%d)\n",
           GST_ELEMENT_NAME (bin), state,type);
 
   g_return_val_if_fail (bin != NULL, FALSE);
@@ -376,19 +476,30 @@ static void
 gst_bin_real_destroy (GtkObject *object)
 {
   GstBin *bin = GST_BIN (object);
-  GList *children;
+  GList *children, *orig;
   GstElement *child;
 
-  GST_DEBUG (0,"in gst_bin_real_destroy()\n");
+  GST_DEBUG (GST_CAT_REFCOUNTING,"destroy()\n");
 
-  children = bin->children;
-  while (children) {
-    child = GST_ELEMENT (children->data);
-    gst_element_destroy (child);
-    children = g_list_next (children);
+  if (bin->children) {
+    orig = children = g_list_copy (bin->children);
+    while (children) {
+      child = GST_ELEMENT (children->data);
+      //gst_object_unref (GST_OBJECT (child));
+      //gst_object_unparent (GST_OBJECT (child));
+      gst_bin_remove (bin, child);
+      children = g_list_next (children);
+    }
+    g_list_free (orig);
+    g_list_free (bin->children);
   }
+  bin->children = NULL;
+  bin->numchildren = 0;
+
+  g_cond_free (bin->eoscond);
 
-  g_list_free (bin->children);
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    GTK_OBJECT_CLASS (parent_class)->destroy (object);
 }
 
 /**
@@ -416,7 +527,7 @@ gst_bin_get_by_name (GstBin *bin,
   children = bin->children;
   while (children) {
     child = GST_ELEMENT (children->data);
-    if (!strcmp (gst_object_get_name (GST_OBJECT (child)),name))
+    if (!strcmp (GST_OBJECT_NAME(child),name))
       return child;
     if (GST_IS_BIN (child)) {
       GstElement *res = gst_bin_get_by_name (GST_BIN (child), name);
@@ -521,7 +632,7 @@ gst_bin_restore_thyself (GstObject *object,
       childlist = field->xmlChildrenNode;
       while (childlist) {
         if (!strcmp (childlist->name, "element")) {
-          GstElement *element = gst_element_load_thyself (childlist, GST_OBJECT (bin));
+          GstElement *element = gst_element_restore_thyself (childlist, GST_OBJECT (bin));
 
          gst_bin_add (bin, element);
        }
@@ -569,23 +680,6 @@ gst_bin_iterate (GstBin *bin)
   return eos;
 }
 
-/**
- * gst_bin_create_plan:
- * @bin: #GstBin to create the plan for
- *
- * Let the bin figure out how to handle its children.
- */
-void
-gst_bin_create_plan (GstBin *bin)
-{
-  GstBinClass *oclass;
-
-  oclass = GST_BIN_CLASS (GTK_OBJECT (bin)->klass);
-
-  if (oclass->create_plan)
-    (oclass->create_plan) (bin);
-}
-
 /* out internal element fired EOS, we decrement the number of pending EOS childs */
 static void
 gst_bin_received_eos (GstElement *element, GstBin *bin)
@@ -601,290 +695,22 @@ gst_bin_received_eos (GstElement *element, GstBin *bin)
   GST_UNLOCK (bin);
 }
 
-/**
- * gst_bin_schedule:
- * @bin: #GstBin to schedule
- *
- * Let the bin figure out how to handle its children.
- */
-void
-gst_bin_schedule (GstBin *bin)
-{
-  GstBinClass *oclass;
-
-  oclass = GST_BIN_CLASS (GTK_OBJECT (bin)->klass);
-
-  if (oclass->schedule)
-    (oclass->schedule) (bin);
-}
-
 typedef struct {
   gulong offset;
   gulong size;
 } region_struct;
 
 
-static void
-gst_bin_create_plan_func (GstBin *bin)
-{
-  GstElement *manager;
-  GList *elements;
-  GstElement *element;
-#ifdef GST_DEBUG_ENABLED
-  const gchar *elementname;
-#endif
-  GSList *pending = NULL;
-  GstBin *pending_bin;
-
-  GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME  (bin));
-
-  GST_INFO_ELEMENT (GST_CAT_PLANNING, bin, "creating plan");
-
-  // first figure out which element is the manager of this and all child elements
-  // if we're a managing bin ourselves, that'd be us
-  if (GST_FLAG_IS_SET (bin, GST_BIN_FLAG_MANAGER)) {
-    manager = GST_ELEMENT (bin);
-    GST_DEBUG (0,"setting manager to self\n");
-  // otherwise, it's what our parent says it is
-  } else {
-    manager = gst_element_get_manager (GST_ELEMENT (bin));
-    if (!manager) {
-      GST_DEBUG (0,"manager not set for element \"%s\" assuming manager is self\n", GST_ELEMENT_NAME (bin));
-      manager = GST_ELEMENT (bin);
-      GST_FLAG_SET (bin, GST_BIN_FLAG_MANAGER);
-    }
-    GST_DEBUG (0,"setting manager to \"%s\"\n", GST_ELEMENT_NAME (manager));
-  }
-  gst_element_set_manager (GST_ELEMENT (bin), manager);
-
-  // perform the first recursive pass of plan generation
-  // we set the manager of every element but those who manage themselves
-  // the need for cothreads is also determined recursively
-  GST_DEBUG (0,"performing first-phase recursion\n");
-  bin->need_cothreads = bin->use_cothreads;
-  if (bin->need_cothreads)
-    GST_DEBUG (0,"requiring cothreads because we're forced to\n");
-
-  elements = bin->children;
-  while (elements) {
-    element = GST_ELEMENT (elements->data);
-    elements = g_list_next (elements);
-#ifdef GST_DEBUG_ENABLED
-    elementname = GST_ELEMENT_NAME  (element);
-#endif
-    GST_DEBUG (0,"have element \"%s\"\n",elementname);
-
-    // first set their manager
-    GST_DEBUG (0,"setting manager of \"%s\" to \"%s\"\n",elementname,GST_ELEMENT_NAME (manager));
-    gst_element_set_manager (element, manager);
-
-    // we do recursion and such for Bins
-    if (GST_IS_BIN (element)) {
-      // recurse into the child Bin
-      GST_DEBUG (0,"recursing into child Bin \"%s\" with manager \"%s\"\n",elementname,
-                     GST_ELEMENT_NAME (element->manager));
-      gst_bin_create_plan (GST_BIN (element));
-      GST_DEBUG (0,"after recurse got manager \"%s\"\n",
-                     GST_ELEMENT_NAME (element->manager));
-      // check to see if it needs cothreads and isn't self-managing
-      if (((GST_BIN (element))->need_cothreads) && !GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
-        GST_DEBUG (0,"requiring cothreads because child bin \"%s\" does\n",elementname);
-        bin->need_cothreads = TRUE;
-      }
-    } else {
-      // then we need to determine whether they need cothreads
-      // if it's a loop-based element, use cothreads
-      if (element->loopfunc != NULL) {
-        GST_DEBUG (0,"requiring cothreads because \"%s\" is a loop-based element\n",elementname);
-        GST_FLAG_SET (element, GST_ELEMENT_USE_COTHREAD);
-      // if it's a 'complex' element, use cothreads
-      } else if (GST_FLAG_IS_SET (element, GST_ELEMENT_COMPLEX)) {
-        GST_DEBUG (0,"requiring cothreads because \"%s\" is complex\n",elementname);
-        GST_FLAG_SET (element, GST_ELEMENT_USE_COTHREAD);
-      // if the element has more than one sink pad, use cothreads
-      } else if (element->numsinkpads > 1) {
-        GST_DEBUG (0,"requiring cothreads because \"%s\" has more than one sink pad\n",elementname);
-        GST_FLAG_SET (element, GST_ELEMENT_USE_COTHREAD);
-      }
-      if (GST_FLAG_IS_SET (element, GST_ELEMENT_USE_COTHREAD))
-        bin->need_cothreads = TRUE;
-    }
-  }
-
-
-  // if we're not a manager thread, we're done.
-  if (!GST_FLAG_IS_SET (bin, GST_BIN_FLAG_MANAGER)) {
-    GST_DEBUG_LEAVE("(\"%s\")",GST_ELEMENT_NAME (bin));
-    return;
-  }
-
-  // clear previous plan state
-  g_list_free (bin->managed_elements);
-  bin->managed_elements = NULL;
-  bin->num_managed_elements = 0;
-
-  // find all the managed children
-  // here we pull off the trick of walking an entire arbitrary tree without recursion
-  GST_DEBUG (0,"attempting to find all the elements to manage\n");
-  pending = g_slist_prepend (pending, bin);
-  do {
-    // retrieve the top of the stack and pop it
-    pending_bin = GST_BIN (pending->data);
-    pending = g_slist_remove (pending, pending_bin);
-
-    // walk the list of elements, find bins, and do stuff
-    GST_DEBUG (0,"checking Bin \"%s\" for managed elements\n",
-          GST_ELEMENT_NAME  (pending_bin));
-    elements = pending_bin->children;
-    while (elements) {
-      element = GST_ELEMENT (elements->data);
-      elements = g_list_next (elements);
-#ifdef GST_DEBUG_ENABLED
-      elementname = GST_ELEMENT_NAME  (element);
-#endif
-
-      // if it's ours, add it to the list
-      if (element->manager == GST_ELEMENT(bin)) {
-        // if it's a Bin, add it to the list of Bins to check
-        if (GST_IS_BIN (element)) {
-          GST_DEBUG (0,"flattened recurse into \"%s\"\n",elementname);
-          pending = g_slist_prepend (pending, element);
-
-        // otherwise add it to the list of elements
-        } else {
-          GST_DEBUG (0,"found element \"%s\" that I manage\n",elementname);
-          bin->managed_elements = g_list_prepend (bin->managed_elements, element);
-          bin->num_managed_elements++;
-        }
-      }
-      // else it's not ours and we need to wait for EOS notifications
-      else {
-        GST_DEBUG (0,"setting up EOS signal from \"%s\" to \"%s\"\n", elementname,
-                       gst_element_get_name (GST_ELEMENT(bin)->manager));
-        gtk_signal_connect (GTK_OBJECT (element), "eos", gst_bin_received_eos, GST_ELEMENT(bin)->manager);
-        bin->eos_providers = g_list_prepend (bin->eos_providers, element);
-        bin->num_eos_providers++;
-      }
-    }
-  } while (pending);
-
-  GST_DEBUG (0,"have %d elements to manage, implementing plan\n",bin->num_managed_elements);
-
-  gst_bin_schedule(bin);
-
-//  g_print ("gstbin \"%s\", eos providers:%d\n",
-//               GST_ELEMENT_NAME (bin),
-//               bin->num_eos_providers);
-
-  GST_DEBUG_LEAVE("(\"%s\")",GST_ELEMENT_NAME (bin));
-}
-
 static gboolean
 gst_bin_iterate_func (GstBin *bin)
 {
-  GList *chains;
-  _GstBinChain *chain;
-  GList *entries;
-  GstElement *entry;
-  GList *pads;
-  GstPad *pad;
-  GstBuffer *buf = NULL;
-  gint num_scheduled = 0;
-  gboolean eos = FALSE;
-
-  GST_DEBUG_ENTER("(\"%s\")", GST_ELEMENT_NAME (bin));
-
-  g_return_val_if_fail (bin != NULL, TRUE);
-  g_return_val_if_fail (GST_IS_BIN (bin), TRUE);
-  g_return_val_if_fail (GST_STATE (bin) == GST_STATE_PLAYING, TRUE);
-
-  // step through all the chains
-  chains = bin->chains;
-  while (chains) {
-    chain = (_GstBinChain *)(chains->data);
-    chains = g_list_next (chains);
-
-    if (!chain->need_scheduling) continue;
-
-    if (chain->need_cothreads) {
-      GList *entries;
-
-      // all we really have to do is switch to the first child
-      // FIXME this should be lots more intelligent about where to start
-      GST_DEBUG (0,"starting iteration via cothreads\n");
-
-      entries = chain->elements;
-      entry = NULL;
-
-      // find an element with a threadstate to start with
-      while (entries) {
-        entry = GST_ELEMENT (entries->data);
-
-        if (entry->threadstate)
-          break;
-        entries = g_list_next (entries);
-      }
-      // if we couldn't find one, bail out
-      if (entries == NULL)
-        GST_ERROR(GST_ELEMENT(bin),"no cothreaded elements found!");
-
-      GST_FLAG_SET (entry, GST_ELEMENT_COTHREAD_STOPPING);
-      GST_DEBUG (0,"set COTHREAD_STOPPING flag on \"%s\"(@%p)\n",
-            GST_ELEMENT_NAME (entry),entry);
-      cothread_switch (entry->threadstate);
-
-    } else {
-      GST_DEBUG (0,"starting iteration via chain-functions\n");
-
-      entries = chain->entries;
-
-      g_assert (entries != NULL);
-
-      while (entries) {
-        entry = GST_ELEMENT (entries->data);
-        entries = g_list_next (entries);
-
-        GST_DEBUG (0,"have entry \"%s\"\n",GST_ELEMENT_NAME (entry));
-
-        if (GST_IS_BIN (entry)) {
-          gst_bin_iterate (GST_BIN (entry));
-        } else {
-          pads = entry->pads;
-          while (pads) {
-            pad = GST_PAD (pads->data);
-            if (GST_RPAD_DIRECTION(pad) == GST_PAD_SRC) {
-              GST_DEBUG (0,"calling getfunc of %s:%s\n",GST_DEBUG_PAD_NAME(pad));
-              if (GST_REAL_PAD(pad)->getfunc == NULL)
-                fprintf(stderr, "error, no getfunc in \"%s\"\n", GST_ELEMENT_NAME  (entry));
-              else
-                buf = (GST_REAL_PAD(pad)->getfunc)(pad);
-              if (buf) gst_pad_push(pad,buf);
-            }
-            pads = g_list_next (pads);
-          }
-        }
-      }
-    }
-    num_scheduled++;
-  }
-
-  // check if nothing was scheduled that was ours..
-  if (!num_scheduled) {
-    // are there any other elements that are still busy?
-    if (bin->num_eos_providers) {
-      GST_LOCK (bin);
-      GST_DEBUG (0,"waiting for eos providers\n");
-      g_cond_wait (bin->eoscond, GST_GET_LOCK(bin));
-      GST_DEBUG (0,"num eos providers %d\n", bin->num_eos_providers);
-      GST_UNLOCK (bin);
-    }
-    else {
-      gst_element_signal_eos (GST_ELEMENT (bin));
-      eos = TRUE;
-    }
+  // only iterate if this is the manager bin
+  if (GST_ELEMENT_SCHED(bin)->parent == GST_ELEMENT (bin)) {
+    return GST_SCHEDULE_ITERATE(GST_ELEMENT_SCHED(bin));
+  } else {
+    GST_DEBUG (GST_CAT_SCHEDULING, "this bin can't be iterated on!\n");
   }
 
-  GST_DEBUG_LEAVE("(%s)", GST_ELEMENT_NAME (bin));
-  return !eos;
+  return FALSE;
 }
 
index 23b826f..da5d8aa 100644 (file)
@@ -47,6 +47,8 @@ extern GstElementDetails gst_bin_details;
 typedef enum {
   /* this bin is a manager of child elements, i.e. a pipeline or thread */
   GST_BIN_FLAG_MANAGER         = GST_ELEMENT_FLAG_LAST,
+  /* this bin is actually a meta-bin, and may need to be scheduled */
+  GST_BIN_SELF_SCHEDULABLE,
 
   /* we prefer to have cothreads when its an option, over chain-based */
   GST_BIN_FLAG_PREFER_COTHREADS,
@@ -55,8 +57,8 @@ typedef enum {
   GST_BIN_FLAG_LAST            = GST_ELEMENT_FLAG_LAST + 4,
 } GstBinFlags;
 
-typedef struct _GstBin GstBin;
-typedef struct _GstBinClass GstBinClass;
+//typedef struct _GstBin GstBin;
+//typedef struct _GstBinClass GstBinClass;
 typedef struct __GstBinChain _GstBinChain;
 
 struct _GstBin {
@@ -94,9 +96,6 @@ struct _GstBinClass {
   gboolean     (*change_state_type)    (GstBin *bin,
                                         GstElementState state,
                                         GtkType type);
-  /* create a plan for the execution of the bin */
-  void         (*create_plan)          (GstBin *bin);
-  void         (*schedule)             (GstBin *bin);
   /* run a full iteration of operation */
   gboolean     (*iterate)              (GstBin *bin);
 };
@@ -116,6 +115,10 @@ GtkType            gst_bin_get_type                (void);
 GstElement*    gst_bin_new                     (const gchar *name);
 #define                gst_bin_destroy(bin)            gst_object_destroy(GST_OBJECT(bin))
 
+void           gst_bin_set_element_manager     (GstElement *element, GstElement *manager);
+void           gst_bin_add_managed_element     (GstBin *bin, GstElement *element);
+void           gst_bin_remove_managed_element  (GstBin *bin, GstElement *element);
+
 /* add and remove elements from the bin */
 void           gst_bin_add                     (GstBin *bin,
                                                 GstElement *element);
@@ -129,8 +132,6 @@ GstElement* gst_bin_get_by_name_recurse_up  (GstBin *bin,
                                                 const gchar *name);
 GList*         gst_bin_get_list                (GstBin *bin);
 
-void           gst_bin_create_plan             (GstBin *bin);
-void           gst_bin_schedule                (GstBin *bin);
 gboolean       gst_bin_set_state_type          (GstBin *bin,
                                                 GstElementState state,
                                                 GtkType type);
index 23f68e7..7a44084 100644 (file)
@@ -448,7 +448,7 @@ gst_buffer_copy (GstBuffer *buffer)
     // copy the absolute size
     newbuf->size = buffer->size;
     // allocate space for the copy
-    newbuf->data = (guchar *)g_malloc (buffer->data);
+    newbuf->data = (guchar *)g_malloc (buffer->size);
     // copy the data straight across
     memcpy(newbuf,buffer->data,buffer->size);
     // the new maxsize is the same as the size, since we just malloc'd it
index df122b5..0ef1c55 100644 (file)
@@ -476,7 +476,7 @@ static gboolean
 gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
 {
   if (fromcaps->id != tocaps->id) {
-    GST_DEBUG (0,"gstcaps: mime types differ (%s to %s)\n",
+    GST_DEBUG (GST_CAT_CAPS,"mime types differ (%s to %s)\n",
               gst_type_find_by_id (fromcaps->id)->mime, 
               gst_type_find_by_id (tocaps->id)->mime);
     return FALSE;
@@ -487,13 +487,13 @@ gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
       return gst_props_check_compatibility (fromcaps->properties, tocaps->properties);
     }
     else {
-      GST_DEBUG (0,"gstcaps: no source caps\n");
+      GST_DEBUG (GST_CAT_CAPS,"no source caps\n");
       return FALSE;
     }
   }
   else {
     // assume it accepts everything
-    GST_DEBUG (0,"gstcaps: no caps\n");
+    GST_DEBUG (GST_CAT_CAPS,"no caps\n");
     return TRUE;
   }
 }
@@ -512,17 +512,17 @@ gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps)
 {
   if (fromcaps == NULL) {
     if (tocaps == NULL) {
-      GST_DEBUG (0,"gstcaps: no caps\n");
+      GST_DEBUG (GST_CAT_CAPS,"no caps\n");
       return TRUE;
     }
     else {
-      GST_DEBUG (0,"gstcaps: no src but destination caps\n");
+      GST_DEBUG (GST_CAT_CAPS,"no source but destination caps\n");
       return FALSE;
     }
   }
   else {
     if (tocaps == NULL) {
-      GST_DEBUG (0,"gstcaps: src caps and no dest caps\n");
+      GST_DEBUG (GST_CAT_CAPS,"source caps and no destination caps\n");
       return TRUE;
     }
   }
index 8040baf..0c3caad 100644 (file)
@@ -71,7 +71,7 @@ void
 gst_clock_register (GstClock *clock, GstObject *obj)
 {
   if ((GST_ELEMENT(obj))->numsrcpads == 0) {
-    GST_DEBUG (0,"gst_clock: setting registered sink object 0x%p\n", obj);
+    GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting registered sink object 0x%p\n", obj);
     clock->sinkobjects = g_list_append (clock->sinkobjects, obj);
     clock->num++;
   }
@@ -88,7 +88,8 @@ gst_clock_set (GstClock *clock, GstClockTime time)
   g_mutex_lock (clock->lock);
   clock->start_time = now - time;
   g_mutex_unlock (clock->lock);
-  GST_DEBUG (0,"gst_clock: setting clock to %llu %llu %llu\n", time, now, clock->start_time);
+  GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting clock to %llu %llu %llu\n",
+             time, now, clock->start_time);
 }
 
 GstClockTimeDiff
@@ -115,7 +116,7 @@ gst_clock_reset (GstClock *clock)
   clock->start_time = ((guint64)tfnow.tv_sec)*1000000LL+tfnow.tv_usec;
   clock->current_time = clock->start_time;
   clock->adjust = 0LL;
-  GST_DEBUG (0,"gst_clock: setting start clock %llu\n", clock->start_time);
+  GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting start clock %llu\n", clock->start_time);
   g_mutex_unlock (clock->lock);
 }
 
@@ -133,7 +134,8 @@ gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj)
 
   diff = GST_CLOCK_DIFF (time, now);
   // if we are not behind wait a bit
-  GST_DEBUG (0,"gst_clock: %s waiting for time %08llu %08llu %08lld\n", GST_OBJECT_NAME (obj), time, now, diff);
+  GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld\n",
+             GST_OBJECT_NAME (obj), time, now, diff);
 
   g_mutex_unlock (clock->lock);
   if (diff > 10000 ) {
@@ -143,8 +145,9 @@ gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj)
     if (!tfnow.tv_sec) {
       select(0, NULL, NULL, NULL, &tfnow);
     }
-    else GST_DEBUG (0,"gst_clock: %s waiting %u %llu %llu %llu seconds\n", GST_OBJECT_NAME (obj),
-                   (int)tfnow.tv_sec, now, diff, time);
+    else GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting %u %llu %llu %llu seconds\n",
+                    GST_OBJECT_NAME (obj), (int)tfnow.tv_sec, now, diff, time);
   }
-  GST_DEBUG (0,"gst_clock: %s waiting for time %08llu %08llu %08lld done \n", GST_OBJECT_NAME (obj), time, now, diff);
+  GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld done \n", 
+             GST_OBJECT_NAME (obj), time, now, diff);
 }
index 7241b40..37e5e03 100644 (file)
 #include "gstelement.h"
 #include "gstextratypes.h"
 #include "gstbin.h"
+#include "gstscheduler.h"
 #include "gstutils.h"
 
-
 /* Element signals and args */
 enum {
   STATE_CHANGE,
   NEW_PAD,
+  PAD_REMOVED,
   NEW_GHOST_PAD,
+  GHOST_PAD_REMOVED,
   ERROR,
   EOS,
   LAST_SIGNAL
@@ -48,6 +50,10 @@ enum {
 static void                    gst_element_class_init          (GstElementClass *klass);
 static void                    gst_element_init                (GstElement *element);
 
+static void                    gst_element_set_arg             (GtkObject *object, GtkArg *arg, guint id);
+static void                    gst_element_get_arg             (GtkObject *object, GtkArg *arg, guint id);
+
+static void                    gst_element_shutdown            (GtkObject *object);
 static void                    gst_element_real_destroy        (GtkObject *object);
 
 static GstElementStateReturn   gst_element_change_state        (GstElement *element);
@@ -67,8 +73,8 @@ GtkType gst_element_get_type(void) {
       sizeof(GstElementClass),
       (GtkClassInitFunc)gst_element_class_init,
       (GtkObjectInitFunc)gst_element_init,
-      (GtkArgSetFunc)NULL,
-      (GtkArgGetFunc)NULL,
+      (GtkArgSetFunc)gst_element_set_arg,
+      (GtkArgGetFunc)gst_element_get_arg,
       (GtkClassInitFunc)NULL,
     };
     element_type = gtk_type_unique(GST_TYPE_OBJECT,&element_info);
@@ -97,11 +103,21 @@ gst_element_class_init (GstElementClass *klass)
                     GTK_SIGNAL_OFFSET (GstElementClass, new_pad),
                     gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
                     GST_TYPE_PAD);
+  gst_element_signals[PAD_REMOVED] =
+    gtk_signal_new ("pad_removed", GTK_RUN_LAST, gtkobject_class->type,
+                    GTK_SIGNAL_OFFSET (GstElementClass, pad_removed),
+                    gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
+                    GST_TYPE_PAD);
   gst_element_signals[NEW_GHOST_PAD] =
     gtk_signal_new ("new_ghost_pad", GTK_RUN_LAST, gtkobject_class->type,
                     GTK_SIGNAL_OFFSET (GstElementClass, new_ghost_pad),
                     gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
                     GST_TYPE_PAD);
+  gst_element_signals[GHOST_PAD_REMOVED] =
+    gtk_signal_new ("ghost_pad_removed", GTK_RUN_LAST, gtkobject_class->type,
+                    GTK_SIGNAL_OFFSET (GstElementClass, ghost_pad_removed),
+                    gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
+                    GST_TYPE_PAD);
   gst_element_signals[ERROR] =
     gtk_signal_new ("error", GTK_RUN_LAST, gtkobject_class->type,
                     GTK_SIGNAL_OFFSET (GstElementClass, error),
@@ -115,11 +131,15 @@ gst_element_class_init (GstElementClass *klass)
 
   gtk_object_class_add_signals (gtkobject_class, gst_element_signals, LAST_SIGNAL);
 
-  gtkobject_class->destroy =           gst_element_real_destroy;
+  gtkobject_class->set_arg =           GST_DEBUG_FUNCPTR(gst_element_set_arg);
+  gtkobject_class->get_arg =           GST_DEBUG_FUNCPTR(gst_element_get_arg);
+  gtkobject_class->shutdown =          GST_DEBUG_FUNCPTR(gst_element_shutdown);
+  gtkobject_class->destroy =           GST_DEBUG_FUNCPTR(gst_element_real_destroy);
 
-  gstobject_class->save_thyself =      gst_element_save_thyself;
+  gstobject_class->save_thyself =      GST_DEBUG_FUNCPTR(gst_element_save_thyself);
+  gstobject_class->restore_thyself =   GST_DEBUG_FUNCPTR(gst_element_restore_thyself);
 
-  klass->change_state = gst_element_change_state;
+  klass->change_state =                        GST_DEBUG_FUNCPTR(gst_element_change_state);
   klass->elementfactory = NULL;
 }
 
@@ -134,8 +154,38 @@ gst_element_init (GstElement *element)
   element->pads = NULL;
   element->loopfunc = NULL;
   element->threadstate = NULL;
+  element->sched = NULL;
 }
 
+
+static void
+gst_element_set_arg (GtkObject *object, GtkArg *arg, guint id)
+{
+  GstElementClass *oclass = GST_ELEMENT_CLASS (object->klass);
+
+  GST_SCHEDULE_LOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
+
+  if (oclass->set_arg)
+    (oclass->set_arg)(object,arg,id);
+
+  GST_SCHEDULE_UNLOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
+}
+
+
+static void
+gst_element_get_arg (GtkObject *object, GtkArg *arg, guint id)
+{
+  GstElementClass *oclass = GST_ELEMENT_CLASS (object->klass);
+
+  GST_SCHEDULE_LOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
+
+  if (oclass->get_arg)
+    (oclass->get_arg)(object,arg,id);
+
+  GST_SCHEDULE_UNLOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
+}
+
+
 /**
  * gst_element_new:
  *
@@ -237,9 +287,15 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
   g_return_if_fail (pad != NULL);
   g_return_if_fail (GST_IS_PAD (pad));
 
+  // first check to make sure the pad's parent is already set
+  g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
+
+  // then check to see if there's already a pad by that name here
+  g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
+
   /* set the pad's parent */
-  GST_DEBUG (0,"setting parent of pad '%s'(%p) to '%s'(%p)\n",
-        GST_PAD_NAME (pad), pad, GST_ELEMENT_NAME (element), element);
+  GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'\n",
+        GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
   gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
 
   /* add it to the list */
@@ -255,6 +311,36 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
 }
 
 /**
+ * gst_element_remove_pad:
+ * @element: element to remove pad from
+ * @pad: pad to remove
+ *
+ * Remove a pad (connection point) from the element, 
+ */
+void
+gst_element_remove_pad (GstElement *element, GstPad *pad)
+{
+  g_return_if_fail (element != NULL);
+  g_return_if_fail (GST_IS_ELEMENT (element));
+  g_return_if_fail (pad != NULL);
+  g_return_if_fail (GST_IS_PAD (pad));
+
+  g_return_if_fail (GST_PAD_PARENT (pad) == element);
+
+  /* add it to the list */
+  element->pads = g_list_remove (element->pads, pad);
+  element->numpads--;
+  if (gst_pad_get_direction (pad) == GST_PAD_SRC)
+    element->numsrcpads--;
+  else
+    element->numsinkpads--;
+
+  gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[PAD_REMOVED], pad);
+
+  gst_object_unparent (GST_OBJECT (pad));
+}
+
+/**
  * gst_element_add_ghost_pad:
  * @element: element to add ghost pad to
  * @pad: pad from which the new ghost pad will be created
@@ -273,17 +359,22 @@ gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name)
   g_return_if_fail (pad != NULL);
   g_return_if_fail (GST_IS_PAD (pad));
 
-  GST_DEBUG(0,"creating new ghost pad called %s, from pad %s:%s\n",name,GST_DEBUG_PAD_NAME(pad));
+  // then check to see if there's already a pad by that name here
+  g_return_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE);
+
+  GST_DEBUG(GST_CAT_ELEMENT_PADS,"creating new ghost pad called %s, from pad %s:%s\n",
+            name,GST_DEBUG_PAD_NAME(pad));
   ghostpad = gst_ghost_pad_new (name, pad);
 
   /* add it to the list */
-  GST_DEBUG(0,"adding ghost pad %s to element %s\n", name, GST_ELEMENT_NAME (element));
+  GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s\n",
+            name, GST_ELEMENT_NAME (element));
   element->pads = g_list_append (element->pads, ghostpad);
   element->numpads++;
   // set the parent of the ghostpad
   gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
 
-  GST_DEBUG(0,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
+  GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
 
   /* emit the NEW_GHOST_PAD signal */
   gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_GHOST_PAD], ghostpad);
@@ -331,21 +422,18 @@ gst_element_get_pad (GstElement *element, const gchar *name)
   if (!element->numpads)
     return NULL;
 
-  GST_DEBUG(GST_CAT_ELEMENT_PADS,"searching for pad '%s' in element %s\n",
-            name, GST_ELEMENT_NAME (element));
-
   // look through the list, matching by name
   walk = element->pads;
   while (walk) {
     GstPad *pad = GST_PAD(walk->data);
-    if (!strcmp (gst_object_get_name (GST_OBJECT(pad)), name)) {
-      GST_DEBUG(GST_CAT_ELEMENT_PADS,"found pad '%s'\n",name);
+    if (!strcmp (GST_PAD_NAME(pad), name)) {
+      GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad));
       return pad;
     }
     walk = g_list_next (walk);
   }
 
-  GST_DEBUG(GST_CAT_ELEMENT_PADS,"no such pad '%s'\n",name);
+  GST_INFO(GST_CAT_ELEMENT_PADS,"no such pad '%s' in element \"%s\"",name,GST_ELEMENT_NAME(element));
   return NULL;
 }
 
@@ -440,7 +528,7 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *
   GstPadTemplate *newtempl = NULL;
   GList *padlist;
 
-  GST_DEBUG(0,"gst_element_get_padtemplate_by_compatible()\n");
+  GST_DEBUG(GST_CAT_ELEMENT_PADS,"gst_element_get_padtemplate_by_compatible()\n");
 
   g_return_val_if_fail (element != NULL, NULL);
   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
@@ -457,19 +545,19 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *
     // Check direction (must be opposite)
     // Check caps
 
-    GST_DEBUG(0,"checking direction and caps\n");
+    GST_DEBUG(GST_CAT_CAPS,"checking direction and caps\n");
     if (padtempl->direction == GST_PAD_SRC &&
       compattempl->direction == GST_PAD_SINK) {
-      GST_DEBUG(0,"compatible direction: found src pad template\n");
+      GST_DEBUG(GST_CAT_CAPS,"compatible direction: found src pad template\n");
       compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (padtempl),
                                            GST_PADTEMPLATE_CAPS (compattempl));
-      GST_DEBUG(0,"caps are %scompatible\n", (compat?"":"not "));
+      GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
     } else if (padtempl->direction == GST_PAD_SINK &&
               compattempl->direction == GST_PAD_SRC) {
-      GST_DEBUG(0,"compatible direction: found sink pad template\n");
+      GST_DEBUG(GST_CAT_CAPS,"compatible direction: found sink pad template\n");
       compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (compattempl),
                                            GST_PADTEMPLATE_CAPS (padtempl));
-      GST_DEBUG(0,"caps are %scompatible\n", (compat?"":"not "));
+      GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
     }
 
     if (compat) {
@@ -659,7 +747,7 @@ gst_element_disconnect (GstElement *src, const gchar *srcpadname,
 void
 gst_element_error (GstElement *element, const gchar *error)
 {
-  g_error("GstElement: error in element '%s': %s\n", gst_object_get_name (GST_OBJECT (element)), error);
+  g_error("GstElement: error in element '%s': %s\n", GST_ELEMENT_NAME(element), error);
 
   /* FIXME: this is not finished!!! */
 
@@ -689,6 +777,11 @@ gst_element_set_state (GstElement *element, GstElementState state)
 
   g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
+  g_return_val_if_fail (element->sched != NULL, GST_STATE_FAILURE);
+
+  GST_DEBUG_ELEMENT (GST_CAT_STATES,element, "setting state from %s to %s\n",
+                     gst_element_statename(GST_STATE(element)),
+                     gst_element_statename(state));
 
   /* start with the current state */
   curpending = GST_STATE(element);
@@ -702,6 +795,9 @@ gst_element_set_state (GstElement *element, GstElementState state)
     /* set the pending state variable */
     // FIXME: should probably check to see that we don't already have one
     GST_STATE_PENDING (element) = curpending;
+    if (curpending != state)
+      GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"intermediate: setting state to %s\n",
+                         gst_element_statename(curpending));
 
     /* call the state change function so it can set the state */
     oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
@@ -711,7 +807,7 @@ gst_element_set_state (GstElement *element, GstElementState state)
     /* if that outright didn't work, we need to bail right away */
     /* NOTE: this will bail on ASYNC as well! */
     if (return_val == GST_STATE_FAILURE) {
-//      GST_DEBUG (0,"have async return from '%s'\n",GST_ELEMENT_NAME (element));
+      GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"have failed change_state return\n");
       return return_val;
     }
   }
@@ -741,6 +837,7 @@ gst_element_get_factory (GstElement *element)
   return oclass->elementfactory;
 }
 
+
 /**
  * gst_element_change_state:
  * @element: element to change state of
@@ -757,15 +854,48 @@ gst_element_change_state (GstElement *element)
   g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
 
-//  g_print("gst_element_change_state(\"%s\",%d)\n",
-//          element->name,state);
+//  GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "default handler sets state to %s\n",
+//                     gst_element_statename(GST_STATE_PENDING(element)));
+
+  if (GST_STATE_TRANSITION(element) == GST_STATE_PAUSED_TO_PLAYING) {
+    g_return_val_if_fail(GST_ELEMENT_SCHED(element), GST_STATE_FAILURE);
+    if (GST_ELEMENT_PARENT(element))
+      fprintf(stderr,"PAUSED->PLAYING: element \"%s\" has parent \"%s\" and sched %p\n",
+GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
+    GST_SCHEDULE_ENABLE_ELEMENT (element->sched,element);
+  }
+  else if (GST_STATE_TRANSITION(element) == GST_STATE_PLAYING_TO_PAUSED) {
+    if (GST_ELEMENT_PARENT(element))
+      fprintf(stderr,"PLAYING->PAUSED: element \"%s\" has parent \"%s\" and sched %p\n",
+GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
+    GST_SCHEDULE_DISABLE_ELEMENT (element->sched,element);
+  }
 
   GST_STATE (element) = GST_STATE_PENDING (element);
   GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING;
 
+  // note: queues' state_change is a special case because it needs to lock
+  // for synchronization (from another thread).  since this signal may block
+  // or (worse) make another state change, the queue needs to unlock before
+  // calling.  thus, gstqueue.c::gst_queue_state_change() blocks, unblocks,
+  // unlocks, then emits this. 
   gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[STATE_CHANGE],
                    GST_STATE (element));
-  return TRUE;
+  return GST_STATE_SUCCESS;
+}
+
+static void
+gst_element_shutdown (GtkObject *object)
+{
+  GstElement *element = GST_ELEMENT (object);
+
+  GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "shutdown\n");
+
+  if (GST_IS_BIN (GST_OBJECT_PARENT (element)))
+    gst_bin_remove (GST_BIN (GST_OBJECT_PARENT (element)), element);
+
+  if (GTK_OBJECT_CLASS (parent_class)->shutdown)
+    GTK_OBJECT_CLASS (parent_class)->shutdown (object);
 }
 
 static void
@@ -775,16 +905,29 @@ gst_element_real_destroy (GtkObject *object)
   GList *pads;
   GstPad *pad;
 
-//  g_print("in gst_element_real_destroy()\n");
-
-  pads = element->pads;
-  while (pads) {
-    pad = GST_PAD (pads->data);
-    gst_pad_destroy (pad);
-    pads = g_list_next (pads);
+  GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "destroy\n");
+
+  if (element->pads) {
+    GList *orig;
+    orig = pads = g_list_copy (element->pads);
+    while (pads) {
+      pad = GST_PAD (pads->data);
+      //gst_object_destroy (GST_OBJECT (pad));
+      gst_object_ref (GST_OBJECT (pad));
+      gst_element_remove_pad (element, pad);
+      gst_object_unref (GST_OBJECT (pad));
+      pads = g_list_next (pads);
+    }
+    g_list_free (orig);
+    g_list_free (element->pads);
+    element->pads = NULL;
   }
 
-  g_list_free (element->pads);
+  element->numsrcpads = 0;
+  element->numsinkpads = 0;
+
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    GTK_OBJECT_CLASS (parent_class)->destroy (object);
 }
 
 /*
@@ -830,7 +973,7 @@ gst_element_save_thyself (GstObject *object,
 
   oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
 
-  xmlNewChild(parent, NULL, "name", gst_object_get_name (GST_OBJECT (element)));
+  xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
 
   if (oclass->elementfactory != NULL) {
     GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
@@ -839,6 +982,9 @@ gst_element_save_thyself (GstObject *object,
     xmlNewChild (parent, NULL, "version", factory->details->version);
   }
 
+//  if (element->manager)
+//    xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager));
+
   // output all args to the element
   type = GTK_OBJECT_TYPE (element);
   while (type != GTK_TYPE_INVALID) {
@@ -918,7 +1064,7 @@ gst_element_save_thyself (GstObject *object,
 }
 
 /**
- * gst_element_load_thyself:
+ * gst_element_restore_thyself:
  * @self: the xml node
  * @parent: the parent of this object when it's loaded
  *
@@ -927,7 +1073,7 @@ gst_element_save_thyself (GstObject *object,
  * Returns: the new element
  */
 GstElement*
-gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
+gst_element_restore_thyself (xmlNodePtr self, GstObject *parent)
 {
   xmlNodePtr children = self->xmlChildrenNode;
   GstElement *element;
@@ -948,7 +1094,7 @@ gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
   g_return_val_if_fail (name != NULL, NULL);
   g_return_val_if_fail (type != NULL, NULL);
 
-  GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"\n", name, type);
+  GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"", name, type);
 
   element = gst_elementfactory_make (type, name);
 
@@ -1002,32 +1148,33 @@ gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
 }
 
 /**
- * gst_element_set_manager:
+ * gst_element_set_sched:
  * @element: Element to set manager of.
- * @manager: Element to be the manager.
+ * @sched: @GstSchedule to set.
  *
- * Sets the manager of the element.  For internal use only, unless you're
+ * Sets the scheduler of the element.  For internal use only, unless you're
  * writing a new bin subclass.
  */
 void
-gst_element_set_manager (GstElement *element,
-                        GstElement *manager)
+gst_element_set_sched (GstElement *element,
+                        GstSchedule *sched)
 {
-  element->manager = manager;
+  GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p",sched);
+  element->sched = sched;
 }
 
 /**
- * gst_element_get_manager:
+ * gst_element_get_sched:
  * @element: Element to get manager of.
  *
- * Returns the manager of the element.
+ * Returns the scheduler of the element.
  *
- * Returns: Element's manager
+ * Returns: Element's scheduler
  */
-GstElement*
-gst_element_get_manager (GstElement *element)
+GstSchedule*
+gst_element_get_sched (GstElement *element)
 {
-  return element->manager;
+  return element->sched;
 }
 
 /**
@@ -1070,3 +1217,24 @@ gst_element_signal_eos (GstElement *element)
   GST_FLAG_SET(element,GST_ELEMENT_COTHREAD_STOPPING);
 }
 
+
+const gchar *gst_element_statename(int state) {
+  switch (state) {
+#ifdef GST_DEBUG_COLOR
+    case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
+    case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
+    case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
+    case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
+    case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
+    default: return "\033[01;37;41mUNKNOWN!\033[00m";
+#else
+    case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
+    case GST_STATE_NULL: return "NULL";break;
+    case GST_STATE_READY: return "READY";break;
+    case GST_STATE_PLAYING: return "PLAYING";break;
+    case GST_STATE_PAUSED: return "PAUSED";break;
+    default: return "UNKNOWN!";
+#endif
+  }
+  return "";
+}
index cc296c9..212dd4c 100644 (file)
@@ -46,8 +46,8 @@ typedef enum {
   GST_STATE_NONE_PENDING       = 0,
   GST_STATE_NULL               = (1 << 0),
   GST_STATE_READY              = (1 << 1),
-  GST_STATE_PLAYING            = (1 << 2),
-  GST_STATE_PAUSED             = (1 << 3),
+  GST_STATE_PAUSED             = (1 << 2),
+  GST_STATE_PLAYING            = (1 << 3),
 } GstElementState;
 
 typedef enum {
@@ -56,28 +56,19 @@ typedef enum {
   GST_STATE_ASYNC              = 2,
 } GstElementStateReturn;
 
-static inline char *_gst_print_statename(int state) {
-  switch (state) {
-    case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
-    case GST_STATE_NULL: return "NULL";break;
-    case GST_STATE_READY: return "READY";break;
-    case GST_STATE_PLAYING: return "PLAYING";break;
-    case GST_STATE_PAUSED: return "PAUSED";break;
-    default: return "";
-  }
-  return "";
-}
 
+// NOTE: this probably should be done with an #ifdef to decide whether to safe-cast
+// or to just do the non-checking cast.
 #define GST_STATE(obj)                 (GST_ELEMENT(obj)->current_state)
 #define GST_STATE_PENDING(obj)         (GST_ELEMENT(obj)->pending_state)
 
 // Note: using 8 bit shift mostly "just because", it leaves us enough room to grow <g>
 #define GST_STATE_TRANSITION(obj)      ((GST_STATE(obj)<<8) | GST_STATE_PENDING(obj))
 #define GST_STATE_NULL_TO_READY                ((GST_STATE_NULL<<8) | GST_STATE_READY)
-#define GST_STATE_READY_TO_PLAYING     ((GST_STATE_READY<<8) | GST_STATE_PLAYING)
-#define GST_STATE_PLAYING_TO_PAUSED    ((GST_STATE_PLAYING<<8) | GST_STATE_PAUSED)
+#define GST_STATE_READY_TO_PAUSED      ((GST_STATE_READY<<8) | GST_STATE_PAUSED)
 #define GST_STATE_PAUSED_TO_PLAYING    ((GST_STATE_PAUSED<<8) | GST_STATE_PLAYING)
-#define GST_STATE_PLAYING_TO_READY     ((GST_STATE_PLAYING<<8) | GST_STATE_READY)
+#define GST_STATE_PLAYING_TO_PAUSED    ((GST_STATE_PLAYING<<8) | GST_STATE_PAUSED)
+#define GST_STATE_PAUSED_TO_READY      ((GST_STATE_PAUSED<<8) | GST_STATE_READY)
 #define GST_STATE_READY_TO_NULL                ((GST_STATE_READY<<8) | GST_STATE_NULL)
 
 #define GST_TYPE_ELEMENT \
@@ -104,6 +95,9 @@ typedef enum {
 
   /***** !!!!! need to have a flag that says that an element must
     *not* be an entry into a scheduling chain !!!!! *****/
+  /* this element for some reason doesn't obey COTHREAD_STOPPING, or
+     has some other reason why it can't be the entry */
+  GST_ELEMENT_NO_ENTRY,
 
   /* there is a new loopfunction ready for placement */
   GST_ELEMENT_NEW_LOOPFUNC,
@@ -116,7 +110,7 @@ typedef enum {
   GST_ELEMENT_EOS,
 
   /* use some padding for future expansion */
-  GST_ELEMENT_FLAG_LAST                = GST_OBJECT_FLAG_LAST + 8,
+  GST_ELEMENT_FLAG_LAST                = GST_OBJECT_FLAG_LAST + 12,
 } GstElementFlags;
 
 #define GST_ELEMENT_IS_THREAD_SUGGESTED(obj)   (GST_FLAG_IS_SET(obj,GST_ELEMENT_THREAD_SUGGESTED))
@@ -125,10 +119,12 @@ typedef enum {
 
 #define GST_ELEMENT_NAME(obj)                  (GST_OBJECT_NAME(obj))
 #define GST_ELEMENT_PARENT(obj)                        (GST_OBJECT_PARENT(obj))
+#define GST_ELEMENT_MANAGER(obj)               (((GstElement*)(obj))->manager)
+#define GST_ELEMENT_SCHED(obj)                 (((GstElement*)(obj))->sched)
 #define GST_ELEMENT_PADS(obj)                  ((obj)->pads)
 
-typedef struct _GstElement GstElement;
-typedef struct _GstElementClass GstElementClass;
+//typedef struct _GstElement GstElement;
+//typedef struct _GstElementClass GstElementClass;
 typedef struct _GstElementDetails GstElementDetails;
 typedef struct _GstElementFactory GstElementFactory;
 
@@ -149,6 +145,7 @@ struct _GstElement {
   GList *pads;
 
   GstElement *manager;
+  GstSchedule *sched;
 };
 
 struct _GstElementClass {
@@ -158,11 +155,21 @@ struct _GstElementClass {
   GstElementFactory *elementfactory;
 
   /* signal callbacks */
-  void (*state_change) (GstElement *element,GstElementState state);
-  void (*new_pad)      (GstElement *element,GstPad *pad);
-  void (*new_ghost_pad) (GstElement *element,GstPad *pad);
-  void (*error)                (GstElement *element,gchar *error);
-  void (*eos)          (GstElement *element);
+  void (*state_change)         (GstElement *element,GstElementState state);
+  void (*new_pad)              (GstElement *element,GstPad *pad);
+  void (*pad_removed)          (GstElement *element,GstPad *pad);
+  void (*new_ghost_pad)        (GstElement *element,GstPad *pad);
+  void (*ghost_pad_removed)    (GstElement *element,GstPad *pad);
+  void (*error)                        (GstElement *element,gchar *error);
+  void (*eos)                  (GstElement *element);
+
+  /* local pointers for get/set */
+  void (*set_arg) (GtkObject *object,
+                   GtkArg    *arg,
+                   guint      arg_id);
+  void (*get_arg) (GtkObject *object,
+                   GtkArg    *arg,
+                   guint      arg_id);      
 
   /* change the element state */
   GstElementStateReturn (*change_state)                (GstElement *element);
@@ -202,10 +209,11 @@ const gchar*            gst_element_get_name            (GstElement *element);
 void                    gst_element_set_parent          (GstElement *element, GstObject *parent);
 GstObject*              gst_element_get_parent          (GstElement *element);
 
-void                   gst_element_set_manager         (GstElement *element, GstElement *manager);
-GstElement*            gst_element_get_manager         (GstElement *element);
+void                   gst_element_set_sched           (GstElement *element, GstSchedule *sched);
+GstSchedule*           gst_element_get_sched           (GstElement *element);
 
 void                   gst_element_add_pad             (GstElement *element, GstPad *pad);
+void                   gst_element_remove_pad          (GstElement *element, GstPad *pad);
 GstPad*                        gst_element_get_pad             (GstElement *element, const gchar *name);
 GList*                 gst_element_get_pad_list        (GstElement *element);
 GList*                 gst_element_get_padtemplate_list        (GstElement *element);
@@ -232,7 +240,7 @@ void                        gst_element_error               (GstElement *element, const gchar *error);
 GstElementFactory*     gst_element_get_factory         (GstElement *element);
 
 /* XML write and read */
-GstElement*            gst_element_load_thyself        (xmlNodePtr self, GstObject *parent);
+GstElement*            gst_element_restore_thyself     (xmlNodePtr self, GstObject *parent);
 
 
 /*
@@ -264,9 +272,13 @@ GstElement*                gst_elementfactory_create               (GstElementFactory *factory,
 /* FIXME this name is wrong, probably so is the one above it */
 GstElement*            gst_elementfactory_make                 (const gchar *factoryname, const gchar *name);
 
+
 xmlNodePtr             gst_elementfactory_save_thyself         (GstElementFactory *factory, xmlNodePtr parent);
 GstElementFactory*     gst_elementfactory_load_thyself         (xmlNodePtr parent);
 
+
+const gchar *          gst_element_statename                   (int state);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index 997cb20..9c4bc42 100644 (file)
@@ -68,8 +68,6 @@ gst_elementfactory_find (const gchar *name)
 
   g_return_val_if_fail(name != NULL, NULL);
 
-  GST_DEBUG (0,"gstelementfactory: find \"%s\"\n", name);
-
   walk = _gst_elementfactories;
   while (walk) {
     factory = (GstElementFactory *)(walk->data);
@@ -78,6 +76,8 @@ gst_elementfactory_find (const gchar *name)
     walk = g_list_next(walk);
   }
 
+  // this should be an ERROR
+  GST_DEBUG (GST_CAT_ELEMENTFACTORY,"no such elementfactoryfactory \"%s\"\n", name);
   return NULL;
 }
 
@@ -148,7 +148,8 @@ gst_elementfactory_create (GstElementFactory *factory,
   g_return_val_if_fail(factory != NULL, NULL);
   g_return_val_if_fail(name != NULL, NULL);
 
-  GST_DEBUG (0,"gstelementfactory: create \"%s\" \"%s\"\n", factory->name, name);
+  GST_DEBUG (GST_CAT_ELEMENTFACTORY,"creating element from factory \"%s\" with name \"%s\"\n", 
+             factory->name, name);
 
   // it's not loaded, try to load the plugin
   if (factory->type == 0) {
@@ -160,12 +161,11 @@ gst_elementfactory_create (GstElementFactory *factory,
   // create an instance of the element
   element = GST_ELEMENT(gtk_type_new(factory->type));
   g_assert(element != NULL);
-  gst_object_ref(GST_OBJECT(element));
 
   // attempt to set the elemenfactory class pointer if necessary
   oclass = GST_ELEMENT_CLASS(GTK_OBJECT(element)->klass);
   if (oclass->elementfactory == NULL) {
-    GST_DEBUG (0,"gstelementfactory: class %s\n", factory->name);
+    GST_DEBUG (GST_CAT_ELEMENTFACTORY,"class %s\n", factory->name);
     oclass->elementfactory = factory;
   }
 
@@ -194,7 +194,7 @@ gst_elementfactory_make (const gchar *factoryname, const gchar *name)
   g_return_val_if_fail(factoryname != NULL, NULL);
   g_return_val_if_fail(name != NULL, NULL);
 
-  GST_DEBUG (0,"gstelementfactory: make \"%s\" \"%s\"\n", factoryname, name);
+//  GST_DEBUG (GST_CAT_ELEMENTFACTORY,"gstelementfactory: make \"%s\" \"%s\"\n", factoryname, name);
 
   //gst_plugin_load_elementfactory(factoryname);
   factory = gst_elementfactory_find(factoryname);
index 1526372..46ccbde 100644 (file)
@@ -20,6 +20,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#include <dlfcn.h>
 #include "gst_private.h"
 #include "gstelement.h"
 #include "gstpad.h"
 extern gchar *_gst_progname;
 
 
-/***** DEBUG system *****/
-GHashTable *__gst_function_pointers = NULL;
-
-
-
-/***** INFO system *****/
-GstInfoHandler _gst_info_handler = gst_default_info_handler;
-#ifdef GST_INFO_ENABLED_VERBOSE
-guint32 _gst_info_categories = 0xffffffff;
-#else
-guint32 _gst_info_categories = 0x00000001;
-#endif
-
+/***** Categories and colorization *****/
 static gchar *_gst_info_category_strings[] = {
   "GST_INIT",
   "COTHREADS",
@@ -48,9 +37,9 @@ static gchar *_gst_info_category_strings[] = {
   "AUTOPLUG_ATTEMPT",
   "PARENTAGE",
   "STATES",
-  "PLANING",
+  "PLANNING",
   "SCHEDULING",
-  "OPERATION",
+  "DATAFLOW",
   "BUFFER",
   "CAPS",
   "CLOCK",
@@ -66,48 +55,195 @@ static gchar *_gst_info_category_strings[] = {
   "TYPES",
   "XML",
   "NEGOTIATION",
+  "REFCOUNTING",
 };
 
-const gchar *_gst_category_colors[] = {
-  [GST_CAT_GST_INIT] = "00;37",
-  [GST_CAT_COTHREADS] = "00;32",
-  [GST_CAT_COTHREAD_SWITCH] = "00;32",
-  [GST_CAT_AUTOPLUG] = "00;34",
-  [GST_CAT_AUTOPLUG_ATTEMPT] = "00;34",
-  [GST_CAT_PARENTAGE] = "",
-  [GST_CAT_STATES] = "00;31",
-  [GST_CAT_PLANNING] = "00;35",
-  [GST_CAT_SCHEDULING] = "00;35",
-  [GST_CAT_DATAFLOW] = "00;32",
-  [GST_CAT_BUFFER] = "00;32",
-  [GST_CAT_CAPS] = "",
-  [GST_CAT_CLOCK] = "",
-  [GST_CAT_ELEMENT_PADS] = "",
-  [GST_CAT_ELEMENTFACTORY] = "",
-  [GST_CAT_PADS] = "",
-  [GST_CAT_PIPELINE] = "",
-  [GST_CAT_PLUGIN_LOADING] = "00;36",
-  [GST_CAT_PLUGIN_ERRORS] = "05;31",
-  [GST_CAT_PLUGIN_INFO] = "00;36",
-  [GST_CAT_PROPERTIES] = "",
-  [GST_CAT_THREAD] = "00;31",
-  [GST_CAT_TYPES] = "",
-  [GST_CAT_XML] = "",
-  [GST_CAT_NEGOTIATION] = "",
-
-  [31] = "",
-};
+/**
+ * gst_get_category_name:
+ * @category: the category to return the name of
+ *
+ * Returns: string containing the name of the category
+ */
+const gchar *
+gst_get_category_name (gint category) {
+  if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
+    return _gst_info_category_strings[category];
+  else
+    return NULL;
+}
+
 
+/*
+ * Attribute codes:
+ * 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
+ * Text color codes:
+ * 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
+ * Background color codes:
+ * 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
+ */
+const gchar *_gst_category_colors[32] = {
+  [GST_CAT_GST_INIT]           = "07;37",
+  [GST_CAT_COTHREADS]          = "00;32",
+  [GST_CAT_COTHREAD_SWITCH]    = "00;37;42",
+  [GST_CAT_AUTOPLUG]           = "00;34",
+  [GST_CAT_AUTOPLUG_ATTEMPT]   = "00;36;44",
+  [GST_CAT_PARENTAGE]          = "01;37;41",           // !!
+  [GST_CAT_STATES]             = "00;31",
+  [GST_CAT_PLANNING]           = "07;35",
+  [GST_CAT_SCHEDULING]         = "00;35",
+  [GST_CAT_DATAFLOW]           = "00;32",
+  [GST_CAT_BUFFER]             = "00;32",
+  [GST_CAT_CAPS]               = "04;34",
+  [GST_CAT_CLOCK]              = "00;33",              // !!
+  [GST_CAT_ELEMENT_PADS]       = "01;37;41",           // !!
+  [GST_CAT_ELEMENTFACTORY]     = "01;37;41",           // !!
+  [GST_CAT_PADS]               = "01;37;41",           // !!
+  [GST_CAT_PIPELINE]           = "01;37;41",           // !!
+  [GST_CAT_PLUGIN_LOADING]     = "00;36",
+  [GST_CAT_PLUGIN_ERRORS]      = "05;31",
+  [GST_CAT_PLUGIN_INFO]                = "00;36",
+  [GST_CAT_PROPERTIES]         = "00;37;44",           // !!
+  [GST_CAT_THREAD]             = "00;31",
+  [GST_CAT_TYPES]              = "01;37;41",           // !!
+  [GST_CAT_XML]                        = "01;37;41",           // !!
+  [GST_CAT_NEGOTIATION]                = "07;34",
+  [GST_CAT_REFCOUNTING]                = "00;34:42",
+
+  [31]                         = "",
+};
 
-/* colorization hash */
+/* colorization hash - DEPRACATED in favor of above */
 inline gint _gst_debug_stringhash_color(gchar *file) {
-  int filecolor;
+  int filecolor = 0;
   while (file[0]) filecolor += *(char *)(file++);
   filecolor = (filecolor % 6) + 31;
   return filecolor;
 }
 
 
+
+/***** DEBUG system *****/
+GstDebugHandler _gst_debug_handler = gst_default_debug_handler;
+guint32 _gst_debug_categories = 0x00000000;
+
+/**
+ * gst_default_debug_handler:
+ * @category: category of the DEBUG message
+ * @file: the file the DEBUG occurs in
+ * @function: the function the DEBUG occurs in
+ * @line: the line number in the file
+ * @debug_string: the current debug_string in the function, if any
+ * @element: pointer to the #GstElement in question
+ * @string: the actual DEBUG string
+ *
+ * Prints out the DEBUG mesage in a variant of the following form:
+ *
+ *   DEBUG(pid:cid):gst_function:542(args): [elementname] something neat happened
+ */
+void
+gst_default_debug_handler (gint category, gboolean incore, gchar *file, gchar *function,
+                            gint line, gchar *debug_string,
+                            void *element, gchar *string)
+{
+  gchar *empty = "";
+  gchar *elementname = empty,*location = empty;
+  int pthread_id = getpid();
+  int cothread_id = cothread_getcurrent();
+#ifdef GST_DEBUG_COLOR
+  int pthread_color = pthread_id%6 + 31;
+  int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
+#endif
+
+  if (debug_string == NULL) debug_string = "";
+//  if (category != GST_CAT_GST_INIT)
+    location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
+  if (element && GST_IS_ELEMENT (element))
+#ifdef GST_DEBUG_COLOR
+    elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
+#else
+    elementname = g_strdup_printf (" [%s]", GST_OBJECT_NAME (element));
+#endif
+
+#ifdef GST_DEBUG_COLOR
+  fprintf(stderr,"DEBUG(\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
+          "%s;%sm%s%s\033[00m %s",
+          pthread_color,pthread_id,cothread_color,cothread_id,incore?"00":"01",
+          _gst_category_colors[category],location,elementname,string);
+#else
+  fprintf(stderr,"DEBUG(%5d:%2d)%s%s %s",
+          pthread_id,cothread_id,location,elementname,string);
+#endif /* GST_DEBUG_COLOR */
+
+  if (location != empty) g_free(location);
+  if (elementname != empty) g_free(elementname);
+
+  g_free(string);
+}
+
+
+/**
+ * gst_debug_set_categories:
+ * @categories: bitmask of DEBUG categories to enable
+ *
+ * Enable the output of DEBUG categories based on the given bitmask.
+ * The bit for any given category is (1 << GST_CAT_...).
+ */
+void
+gst_debug_set_categories (guint32 categories) {
+  _gst_debug_categories = categories;
+  if (categories)
+    GST_INFO (0, "setting DEBUG categories to 0x%08X",categories);
+}
+
+/**
+ * gst_debug_get_categories:
+ *
+ * Returns: the current bitmask of enabled DEBUG categories
+ * The bit for any given category is (1 << GST_CAT_...).
+ */
+guint32
+gst_debug_get_categories () {
+  return _gst_debug_categories;
+}
+
+/**
+ * gst_debug_enable_category:
+ * @category: the category to enable
+ *
+ * Enables the given GST_CAT_... DEBUG category.
+ */
+void
+gst_debug_enable_category (gint category) {
+  _gst_debug_categories |= (1 << category);
+  if (_gst_debug_categories)
+    GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
+}
+
+/**
+ * gst_debug_disable_category:
+ * @category: the category to disable
+ *
+ * Disables the given GST_CAT_... DEBUG category.
+ */
+void
+gst_debug_disable_category (gint category) {
+  _gst_debug_categories &= ~ (1 << category);
+  if (_gst_debug_categories)
+    GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
+}
+
+
+
+
+/***** INFO system *****/
+GstInfoHandler _gst_info_handler = gst_default_info_handler;
+#ifdef GST_INFO_ENABLED_VERBOSE
+guint32 _gst_info_categories = 0xffffffff;
+#else
+guint32 _gst_info_categories = 0x00000001;
+#endif
+
+
 /**
  * gst_default_info_handler:
  * @category: category of the INFO message
@@ -123,12 +259,18 @@ inline gint _gst_debug_stringhash_color(gchar *file) {
  *   INFO:gst_function:542(args): [elementname] something neat happened
  */
 void
-gst_default_info_handler (gint category, gchar *file, gchar *function,
+gst_default_info_handler (gint category, gboolean incore,gchar *file, gchar *function,
                            gint line, gchar *debug_string,
                            void *element, gchar *string)
 {
   gchar *empty = "";
   gchar *elementname = empty,*location = empty;
+  int pthread_id = getpid();
+  int cothread_id = cothread_getcurrent();
+#ifdef GST_DEBUG_COLOR
+  int pthread_color = pthread_id%6 + 31;
+  int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
+#endif
 
   if (debug_string == NULL) debug_string = "";
   if (category != GST_CAT_GST_INIT)
@@ -138,15 +280,17 @@ gst_default_info_handler (gint category, gchar *file, gchar *function,
 
 #ifdef GST_DEBUG_ENABLED
   #ifdef GST_DEBUG_COLOR
-    fprintf(stderr,"INFO(%d:%d):\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
-            getpid(),cothread_getcurrent(),_gst_category_colors[category],location,elementname,string);
+    fprintf(stderr,"\033[01mINFO\033[00m (\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
+            GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
+            pthread_color,pthread_id,cothread_color,cothread_id,
+            _gst_category_colors[category],location,elementname,string);
   #else
-    fprintf(stderr,"INFO(%d:%d):%s%s %s\n",
-            getpid(),cothread_getcurrent(),location,elementname,string);
+    fprintf(stderr,"INFO (%5d:%2d)%s%s %s\n",
+            pthread_id,cothread_id,location,elementname,string);
   #endif /* GST_DEBUG_COLOR */
 #else
   #ifdef GST_DEBUG_COLOR
-    fprintf(stderr,"INFO:\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
+    fprintf(stderr,"\033[01mINFO\033[00m:\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
             location,elementname,_gst_category_colors[category],string);
   #else
     fprintf(stderr,"INFO:%s%s %s\n",
@@ -213,77 +357,6 @@ gst_info_disable_category (gint category) {
 
 
 
-/***** DEBUG system *****/
-guint32 _gst_debug_categories = 0x00000000;
-
-
-/**
- * gst_debug_set_categories:
- * @categories: bitmask of DEBUG categories to enable
- *
- * Enable the output of DEBUG categories based on the given bitmask.
- * The bit for any given category is (1 << GST_CAT_...).
- */
-void
-gst_debug_set_categories (guint32 categories) {
-  _gst_debug_categories = categories;
-  if (categories)
-    GST_INFO (0, "setting DEBUG categories to 0x%08X",categories);
-}
-
-/**
- * gst_debug_get_categories:
- *
- * Returns: the current bitmask of enabled DEBUG categories
- * The bit for any given category is (1 << GST_CAT_...).
- */
-guint32
-gst_debug_get_categories () {
-  return _gst_debug_categories;
-}
-
-/**
- * gst_debug_enable_category:
- * @category: the category to enable
- *
- * Enables the given GST_CAT_... DEBUG category.
- */
-void
-gst_debug_enable_category (gint category) {
-  _gst_debug_categories |= (1 << category);
-  if (_gst_debug_categories)
-    GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
-}
-
-/**
- * gst_debug_disable_category:
- * @category: the category to disable
- *
- * Disables the given GST_CAT_... DEBUG category.
- */
-void
-gst_debug_disable_category (gint category) {
-  _gst_debug_categories &= ~ (1 << category);
-  if (_gst_debug_categories)
-    GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
-}
-
-/**
- * gst_get_category_name:
- * @category: the category to return the name of
- *
- * Returns: string containing the name of the category
- */
-const gchar *
-gst_get_category_name (gint category) {
-  if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
-    return _gst_info_category_strings[category];
-  else
-    return NULL;
-}
-
-
-
 /***** ERROR system *****/
 GstErrorHandler _gst_error_handler = gst_default_error_handler;
 
@@ -364,3 +437,24 @@ gst_default_error_handler (gchar *file, gchar *function,
 
   exit(1);
 }
+
+
+
+/***** DEBUG system *****/
+GHashTable *__gst_function_pointers = NULL;
+
+gchar *
+_gst_debug_nameof_funcptr (void *ptr)
+{
+  gchar *ptrname;
+  Dl_info dlinfo;
+  if (__gst_function_pointers) {
+    if ((ptrname = g_hash_table_lookup(__gst_function_pointers,ptr)))
+      return g_strdup(ptrname);
+  } else if (dladdr(ptr,&dlinfo) && dlinfo.dli_sname) {
+    return g_strdup(dlinfo.dli_sname);
+  } else {
+    return g_strdup_printf("%p",ptr);
+  }
+  return NULL;
+}
index 620d809..71fdba9 100644 (file)
 #include "cothreads.h"
 
 
+/***** are we in the core or not? *****/
+#ifdef __GST_PRIVATE_H__
+  #define _GST_DEBUG_INCORE TRUE
+#else
+  #define _GST_DEBUG_INCORE FALSE
+#endif
+
+
 /* colorization stuff */
 #ifdef GST_DEBUG_COLOR
   #ifdef __GST_PRIVATE_H__   /* FIXME this should be some libgst.la -specific thing */
@@ -47,13 +55,51 @@ gint _gst_debug_stringhash_color(gchar *file);
 
 
 
+/**********************************************************************
+ * Categories
+ **********************************************************************/
+
+const gchar *  gst_get_category_name   (gint category);
+
+enum {
+  GST_CAT_GST_INIT = 0,                // Library initialization
+  GST_CAT_COTHREADS,           // Cothread creation, etc.
+  GST_CAT_COTHREAD_SWITCH,     // Cothread switching
+  GST_CAT_AUTOPLUG,            // Successful autoplug results
+  GST_CAT_AUTOPLUG_ATTEMPT,    // Attempted autoplug operations
+  GST_CAT_PARENTAGE,           // GstBin parentage issues
+  GST_CAT_STATES,              // State changes and such
+  GST_CAT_PLANNING,            // Plan generation
+  GST_CAT_SCHEDULING,          // Schedule construction
+  GST_CAT_DATAFLOW,            // Events during actual data movement
+  GST_CAT_BUFFER,              // Buffer creation/destruction
+  GST_CAT_CAPS,                        // Capabilities matching
+  GST_CAT_CLOCK,               // Clocking
+  GST_CAT_ELEMENT_PADS,                // Element pad management
+  GST_CAT_ELEMENTFACTORY,      // Elementfactory stuff
+  GST_CAT_PADS,                        // Pad creation/connection
+  GST_CAT_PIPELINE,            // Pipeline stuff
+  GST_CAT_PLUGIN_LOADING,      // Plugin loading
+  GST_CAT_PLUGIN_ERRORS,       // Errors during plugin loading
+  GST_CAT_PLUGIN_INFO,         // Plugin state information
+  GST_CAT_PROPERTIES,          // Properties
+  GST_CAT_THREAD,              // Thread creation/management
+  GST_CAT_TYPES,               // Typing
+  GST_CAT_XML,                 // XML load/save of everything
+  GST_CAT_NEGOTIATION,         // Caps Negotiation stuff
+  GST_CAT_REFCOUNTING,         // Ref Counting stuff
+
+  GST_CAT_MAX_CATEGORY = 31
+};
+
+extern const gchar *_gst_category_colors[32];
+
+
 
 /**********************************************************************
  * DEBUG system
  **********************************************************************/
 
-extern guint32 _gst_debug_categories;
-
 /* for include files that make too much noise normally */
 #ifdef GST_DEBUG_FORCE_DISABLE
 #undef GST_DEBUG_ENABLED
@@ -69,109 +115,69 @@ extern guint32 _gst_debug_categories;
 //#define GST_DEBUG_ENABLE_CATEGORIES 0x00000000
 //#endif
 
-/* fallback, this should probably be a 'weak' symbol or something */
-G_GNUC_UNUSED static gchar *_debug_string = NULL;
 
-#ifdef GST_DEBUG_COLOR
-  #ifdef _GST_COLOR_CODE
-#warning have a coded debug
-    #define GST_DEBUG_PREFIX(cat,format,args...) \
-"DEBUG(%d:%d)\033[" _GST_COLOR_CODE "m" __PRETTY_FUNCTION__ ":%d\033[00m" format , \
-getpid() , cothread_getcurrent() , __LINE__ , ## args
-  #else
-    #define GST_DEBUG_PREFIX(cat,format,args...) \
-"DEBUG(%d:%d)\033[" GST_DEBUG_CHAR_MODE ";%sm" __PRETTY_FUNCTION__ ":%d\033[00m" format , \
-getpid() , cothread_getcurrent() , _gst_category_colors[cat] , __LINE__ , ## args
-  #endif /* _GST_COLOR_CODE */
-#else
-  #define GST_DEBUG_PREFIX(cat,format,args...) \
-"DEBUG(%d:%d)" __PRETTY_FUNCTION__ ":%d" format , getpid() ,cothread_getcurrent() , __LINE__ , ## args
-#endif
+typedef void (*GstDebugHandler) (gint category,gboolean core,gchar *file,gchar *function,
+                                 gint line,gchar *debug_string,
+                                 void *element,gchar *string);
 
+void gst_default_debug_handler (gint category,gboolean incore,gchar *file,gchar *function,
+                                gint line,gchar *debug_string,
+                                void *element,gchar *string);
 
-#ifdef GST_DEBUG_ENABLED
-#define GST_DEBUG(cat,format,args...) G_STMT_START{ \
-  if (((1<<cat) & GST_DEBUG_ENABLE_CATEGORIES) && \
-      ((1<<cat) & _gst_debug_categories)) \
-    (_debug_string != NULL) ? \
-      fprintf(stderr,GST_DEBUG_PREFIX(cat,"%s: "format , _debug_string , ## args )) : \
-      fprintf(stderr,GST_DEBUG_PREFIX(cat,": "format , ## args )); \
-}G_STMT_END
+extern guint32 _gst_debug_categories;
+extern GstDebugHandler _gst_debug_handler;
 
-#define GST_DEBUG_NOPREFIX(cat,format,args...) G_STMT_START{ \
-  if (((1<<cat) & GST_DEBUG_ENABLE_CATEGORIES) && \
-      ((1<<cat) & _gst_debug_categories)) \
-    fprintf(stderr,format , ## args ); \
-}G_STMT_END
+/* fallback, this should probably be a 'weak' symbol or something */
+G_GNUC_UNUSED static gchar *_debug_string = NULL;
 
-#define GST_DEBUG_ENTER(format, args...) G_STMT_START{ \
-  if (((1<<31) & GST_DEBUG_ENABLE_CATEGORIES) && \
-      ((1<<31) & _gst_debug_categories)) \
-    fprintf(stderr,GST_DEBUG_PREFIX(31,format": entering\n" , ## args )); \
-}G_STMT_END
 
-// FIXME FIXME FIXME this leaks like crazy
-#define GST_DEBUG_SET_STRING(format, args...) \
-  gchar *_debug_string = g_strdup_printf(format , ## args )
 
-#define GST_DEBUG_ENTER_STRING GST_DEBUG_ENTER("%s",_debug_string)
 
-#define GST_DEBUG_LEAVE(format, args...) G_STMT_START{ \
-  if (((1<<31) & GST_DEBUG_ENABLE_CATEGORIES) && \
-      ((1<<31) & _gst_debug_categories)) \
-    if (_debug_string != NULL) g_free(_debug_string),\
-      fprintf(stderr,GST_DEBUG_PREFIX(31,format": leaving\n" , ## args )); \
+#ifdef GST_DEBUG_ENABLED
+#define GST_DEBUG(cat,format,args...) G_STMT_START{ \
+  if ((1<<cat) & _gst_debug_categories) \
+    _gst_debug_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
+                       NULL,g_strdup_printf( format , ## args )); \
 }G_STMT_END
 
-#define GST_DEBUG_LEAVE_STRING GST_DEBUG_LEAVE("%s",_debug_string)
+#define GST_DEBUG_ELEMENT(cat,element,format,args...) G_STMT_START{ \
+  if ((1<<cat) & _gst_debug_categories) \
+    _gst_debug_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
+                       element,g_strdup_printf( format , ## args )); \
+}G_STMT_END
 
 #else
-#define GST_DEBUG(format, args...)
-#define GST_DEBUG_NOPREFIX(format, args...)
-#define GST_DEBUG_ENTER(format, args...)
-#define GST_DEBUG_LEAVE(format, args...)
-#define GST_DEBUG_SET_STRING(format, args...)
-#define GST_DEBUG_ENTER_STRING
+#define GST_DEBUG(cat,format,args...)
+#define GST_DEBUG_ELEMENT(cat,element,format,args...)
 #endif
 
 
 
+
 /********** some convenience macros for debugging **********/
 #define GST_DEBUG_PAD_NAME(pad) \
   (GST_OBJECT_PARENT(pad) != NULL) ? \
   GST_OBJECT_NAME (GST_OBJECT_PARENT(pad)) : \
   "''", GST_OBJECT_NAME (pad)
 
+#ifdef GST_DEBUG_COLOR
+  #define GST_DEBUG_ENTER(format, args...) GST_DEBUG( 31 , format ": \033[01;37mentering\033[00m\n" , ##args )
+  #define GST_DEBUG_LEAVE(format, args...) GST_DEBUG( 31 , format ": \033[01;37mleaving\033[00m\n" , ##args )
+#else
+  #define GST_DEBUG_ENTER(format, args...) GST_DEBUG( 31 , format ": entering\n" , ##args )
+  #define GST_DEBUG_LEAVE(format, args...) GST_DEBUG( 31 , format ": leaving\n" , ##args )
+#endif
 
 
-/********** function pointer stuff **********/
-extern GHashTable *__gst_function_pointers;
-
-#ifdef GST_DEBUG_ENABLED
-#define GST_DEBUG_FUNCPTR(ptr) _gst_debug_register_funcptr((void *)(ptr), #ptr)
-#define GST_DEBUG_FUNCPTR_NAME(ptr) _gst_debug_nameof_funcptr((void *)ptr)
+/***** Colorized debug for thread ids *****/
+#ifdef GST_DEBUG_COLOR
+  #define GST_DEBUG_THREAD_FORMAT "\033[00;%dm%d\033[00m"
+  #define GST_DEBUG_THREAD_ARGS(id) ( ((id) < 0) ? 37 : ((id) % 6 + 31) ), (id)
 #else
-#define GST_DEBUG_FUNCPTR(ptr) (ptr)
-#define GST_DEBUG_FUNCPTR_NAME(ptr) ""
+  #define GST_DEBUG_THREAD_FORMAT "%d"
+  #define GST_DEBUG_THREAD_ARGS(id) (id)
 #endif
 
-static inline void *
-_gst_debug_register_funcptr (void *ptr, gchar *ptrname) 
-{
-  if (!__gst_function_pointers) __gst_function_pointers = g_hash_table_new(g_direct_hash,g_direct_equal);
-  if (!g_hash_table_lookup(__gst_function_pointers,ptr))
-    g_hash_table_insert(__gst_function_pointers,ptr,ptrname);
-  return ptr;
-}
-
-static inline gchar *
-_gst_debug_nameof_funcptr (void *ptr) 
-{
-  gchar *ptrname = (gchar*)( __gst_function_pointers ? g_hash_table_lookup(__gst_function_pointers,ptr) : NULL );
-// FIXME this must go away, it's a major leak
-  if (!ptrname) return g_strdup_printf("%p",ptr);
-  else return ptrname;
-}
 
 
 /**********************************************************************
@@ -227,11 +233,11 @@ G_GNUC_UNUSED static GModule *_debug_self_module = NULL;
  * INFO system
  **********************************************************************/
 
-typedef void (*GstInfoHandler) (gint category,gchar *file,gchar *function,
+typedef void (*GstInfoHandler) (gint category,gboolean incore,gchar *file,gchar *function,
                                 gint line,gchar *debug_string,
                                 void *element,gchar *string);
 
-void gst_default_info_handler (gint category,gchar *file,gchar *function,
+void gst_default_info_handler (gint category,gboolean incore,gchar *file,gchar *function,
                                gint line,gchar *debug_string,
                                void *element,gchar *string);
 
@@ -250,13 +256,13 @@ extern guint32 _gst_info_categories;
 #ifdef GST_INFO_ENABLED
 #define GST_INFO(cat,format,args...) G_STMT_START{ \
   if ((1<<cat) & _gst_info_categories) \
-    _gst_info_handler(cat,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
+    _gst_info_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
                       NULL,g_strdup_printf( format , ## args )); \
 }G_STMT_END
 
 #define GST_INFO_ELEMENT(cat,element,format,args...) G_STMT_START{ \
   if ((1<<cat) & _gst_info_categories) \
-    _gst_info_handler(cat,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
+    _gst_info_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
                       element,g_strdup_printf( format , ## args )); \
 }G_STMT_END
 
@@ -276,42 +282,6 @@ guint32            gst_debug_get_categories        (void);
 void           gst_debug_enable_category       (gint category);
 void           gst_debug_disable_category      (gint category);
 
-const gchar *  gst_get_category_name   (gint category);
-
-
-enum {
-  GST_CAT_GST_INIT = 0,                // Library initialization
-  GST_CAT_COTHREADS,           // Cothread creation, etc.
-  GST_CAT_COTHREAD_SWITCH,     // Cothread switching
-  GST_CAT_AUTOPLUG,            // Successful autoplug results
-  GST_CAT_AUTOPLUG_ATTEMPT,    // Attempted autoplug operations
-  GST_CAT_PARENTAGE,           // GstBin parentage issues
-  GST_CAT_STATES,              // State changes and such
-  GST_CAT_PLANNING,            // Plan generation
-  GST_CAT_SCHEDULING,          // Schedule construction
-  GST_CAT_DATAFLOW,            // Events during actual data movement
-  GST_CAT_BUFFER,              // Buffer creation/destruction
-  GST_CAT_CAPS,                        // Capabilities matching
-  GST_CAT_CLOCK,               // Clocking
-  GST_CAT_ELEMENT_PADS,                // Element pad management
-  GST_CAT_ELEMENTFACTORY,      // Elementfactory stuff
-  GST_CAT_PADS,                        // Pad creation/connection
-  GST_CAT_PIPELINE,            // Pipeline stuff
-  GST_CAT_PLUGIN_LOADING,      // Plugin loading
-  GST_CAT_PLUGIN_ERRORS,       // Errors during plugin loading
-  GST_CAT_PLUGIN_INFO,         // Plugin state information
-  GST_CAT_PROPERTIES,          // Properties
-  GST_CAT_THREAD,              // Thread creation/management
-  GST_CAT_TYPES,               // Typing
-  GST_CAT_XML,                 // XML load/save of everything
-  GST_CAT_NEGOTIATION,         // Caps Negotiation stuff
-
-  GST_CAT_MAX_CATEGORY,
-};
-
-
-extern const gchar *_gst_category_colors[GST_CAT_MAX_CATEGORY];
-
 
 
 
@@ -339,4 +309,30 @@ extern GstErrorHandler _gst_error_handler;
 
 
 
+
+/********** function pointer stuff **********/
+extern GHashTable *__gst_function_pointers;
+
+
+#if GST_DEBUG_ENABLED
+#define GST_DEBUG_FUNCPTR(ptr) _gst_debug_register_funcptr((void *)(ptr), #ptr)
+#define GST_DEBUG_FUNCPTR_NAME(ptr) _gst_debug_nameof_funcptr((void *)ptr)
+#else
+#define GST_DEBUG_FUNCPTR(ptr) (ptr)
+#define GST_DEBUG_FUNCPTR_NAME(ptr) ""
+#endif
+
+static inline void *
+_gst_debug_register_funcptr (void *ptr, gchar *ptrname) 
+{
+  if (!__gst_function_pointers) __gst_function_pointers = g_hash_table_new(g_direct_hash,g_direct_equal);
+  if (!g_hash_table_lookup(__gst_function_pointers,ptr))
+    g_hash_table_insert(__gst_function_pointers,ptr,ptrname);
+  return ptr;
+}
+
+gchar *_gst_debug_nameof_funcptr (void *ptr);
+
+
+
 #endif /* __GSTINFO_H__ */
index 2e7eafb..82c7e2b 100644 (file)
@@ -53,6 +53,10 @@ static guint gst_signal_object_signals[SO_LAST_SIGNAL] = { 0 };
 static void            gst_object_class_init           (GstObjectClass *klass);
 static void            gst_object_init                 (GstObject *object);
 
+static void            gst_object_real_destroy         (GtkObject *gtk_object);
+static void            gst_object_shutdown             (GtkObject *gtk_object);
+static void            gst_object_finalize             (GtkObject *gtk_object);
+
 static GtkObjectClass *parent_class = NULL;
 static guint gst_object_signals[LAST_SIGNAL] = { 0 };
 
@@ -105,6 +109,10 @@ gst_object_class_init (GstObjectClass *klass)
 
   klass->path_string_separator = "/";
   klass->signal_object = gtk_type_new (gst_signal_object_get_type ());
+
+  gtkobject_class->shutdown = gst_object_shutdown;
+  gtkobject_class->destroy = gst_object_real_destroy;
+  gtkobject_class->finalize = gst_object_finalize;
 }
 
 static void
@@ -118,9 +126,12 @@ gst_object_init (GstObject *object)
 #ifdef HAVE_ATOMIC_H
   atomic_set(&(object->refcount),1);
 #else
-  object->refcount++;
+  object->refcount = 1;
 #endif
   object->parent = NULL;
+
+  object->flags = 0;
+  GST_FLAG_SET (object, GST_FLOATING);
 }
 
 /**
@@ -137,6 +148,122 @@ gst_object_new (void)
 }
 
 /**
+ * gst_object_ref:
+ * @object: GstObject to reference
+ *
+ * Increments the refence count on the object.
+ */
+GstObject*
+gst_object_ref (GstObject *object)
+{
+  g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
+
+  GST_DEBUG (GST_CAT_REFCOUNTING, "ref '%s' %d->%d\n",GST_OBJECT_NAME(object),
+             GTK_OBJECT(object)->ref_count,GTK_OBJECT(object)->ref_count+1);
+
+  gtk_object_ref (GTK_OBJECT (object));
+
+  return object;
+}
+#define gst_object_ref gst_object_ref
+
+/**
+ * gst_object_unref:
+ * @object: GstObject to unreference
+ *
+ * Decrements the refence count on the object.  If reference count hits
+ * zero, destroy the object.
+ */
+void
+gst_object_unref (GstObject *object)
+{
+  g_return_if_fail (GST_IS_OBJECT (object));
+
+  GST_DEBUG (GST_CAT_REFCOUNTING, "unref '%s' %d->%d\n",GST_OBJECT_NAME(object),
+             GTK_OBJECT(object)->ref_count,GTK_OBJECT(object)->ref_count-1);
+
+  gtk_object_unref (GTK_OBJECT (object));
+}
+#define gst_object_unref gst_object_unref
+
+/**
+ * gst_object_sink:
+ * @object: GstObject to sink
+ *
+ * Removes floating reference on an object.  Any newly created object has
+ * a refcount of 1 and is FLOATING.  This function should be used when
+ * creating a new object to symbolically 'take ownership of' the object.
+ */
+void
+gst_object_sink (GstObject *object)
+{
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GST_IS_OBJECT (object));
+
+  GST_DEBUG (GST_CAT_REFCOUNTING, "sink '%s'\n",GST_OBJECT_NAME(object));
+  if (GST_OBJECT_FLOATING (object))
+  {
+    GST_FLAG_UNSET (object, GST_FLOATING);
+    gst_object_unref (object);
+  }
+}
+
+void
+gst_object_destroy (GstObject *object)
+{
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GST_IS_OBJECT (object));
+
+  GST_DEBUG (GST_CAT_REFCOUNTING, "destroy '%s'\n",GST_OBJECT_NAME(object));
+  if (!GST_OBJECT_DESTROYED (object))
+  {
+    /* need to hold a reference count around all class method
+     * invocations.
+     */
+    gst_object_ref (object);
+    GTK_OBJECT (object)->klass->shutdown (GTK_OBJECT (object));
+    gst_object_unref (object);
+  }
+}
+
+static void
+gst_object_shutdown (GtkObject *object)
+{
+  GST_DEBUG (GST_CAT_REFCOUNTING, "shutdown '%s'\n",GST_OBJECT_NAME(object));
+  GST_FLAG_SET (GST_OBJECT (object), GST_DESTROYED);
+  parent_class->shutdown (GTK_OBJECT (object));
+}
+
+/* finilize is called when the object has to free its resources */
+static void
+gst_object_real_destroy (GtkObject *gtk_object)
+{
+  GST_DEBUG (GST_CAT_REFCOUNTING, "destroy '%s'\n",GST_OBJECT_NAME(gtk_object));
+
+  GST_OBJECT_PARENT (gtk_object) = NULL;
+
+  parent_class->destroy (gtk_object);
+}
+
+/* finilize is called when the object has to free its resources */
+static void
+gst_object_finalize (GtkObject *gtk_object)
+{
+  GstObject *object;
+
+  object = GST_OBJECT (gtk_object);
+
+  GST_DEBUG (GST_CAT_REFCOUNTING, "finalize '%s'\n",GST_OBJECT_NAME(object));
+
+  if (object->name != NULL)
+    g_free (object->name);
+
+  g_mutex_free (object->lock);
+
+  parent_class->finalize (gtk_object);
+}
+
+/**
  * gst_object_set_name:
  * @object: GstObject to set the name of
  * @name: new name of object
@@ -315,26 +442,31 @@ gst_object_unref (GstObject *object)
 #endif /* gst_object_unref */
 
 /**
- * gst_object_sink:
- * @object: GstObject to sink
+ * gst_object_check_uniqueness:
+ * @list: a list of #GstObject to check through
+ * @name: the name to search for
  *
- * Removes floating reference on an object.  Any newly created object has
- * a refcount of 1 and is FLOATING.  This function should be used when
- * creating a new object to symbolically 'take ownership of' the object.
+ * This function checks through the list of objects to see if the name
+ * given appears in the list as the name of an object.  It returns TRUE if
+ * the name does not exist in the list.
+ *
+ * Returns: TRUE if the name doesn't appear in the list, FALSE if it does.
  */
-#ifndef gst_object_sink
-void
-gst_object_sink (GstObject *object)
+gboolean
+gst_object_check_uniqueness (GList *list, const gchar *name)
 {
-  g_return_if_fail (object != NULL);
-  g_return_if_fail (GST_IS_OBJECT (object));
+  GstObject *child;
 
-  if (GTK_OBJECT_FLOATING (object)) {
-    GTK_OBJECT_UNSET_FLAGS (object, GTK_FLOATING);
-    gst_object_unref (object);
+  while (list) {
+    child = GST_OBJECT (list->data);
+    list = g_list_next(list);
+      
+    if (strcmp(GST_OBJECT_NAME(child), name) == 0) return FALSE;
   }
+
+  return TRUE;
 }
-#endif /* gst_object_sink */
+
 
 /**
  * gst_object_save_thyself:
@@ -528,6 +660,3 @@ gst_class_signal_emit_by_name (GstObject *object,
 
   gtk_signal_emit_by_name (oclass->signal_object, name, object, self);
 }
-
-
-
index 9e1e6bb..f7e095f 100644 (file)
@@ -28,6 +28,8 @@
 #include <gst/gsttrace.h>
 #include <parser.h>
 
+#include <gst/gsttypes.h>
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -55,10 +57,16 @@ extern "C" {
 #define GST_IS_OBJECT_CLASS(obj) \
   (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_OBJECT))
 
-typedef struct _GstObject GstObject;
-typedef struct _GstObjectClass GstObjectClass;
+//typedef struct _GstObject GstObject;
+//typedef struct _GstObjectClass GstObjectClass;
+//
+typedef enum
+{
+  GST_DESTROYED   = 0,
+  GST_FLOATING,
 
-#define GST_OBJECT_FLAG_LAST 4
+  GST_OBJECT_FLAG_LAST   = 4,
+} GstObjectFlags;
 
 struct _GstObject {
   GtkObject object;
@@ -76,6 +84,8 @@ struct _GstObject {
 
   /* this objects parent */
   GstObject *parent;
+
+  guint32 flags;
 };
 
 struct _GstObjectClass {
@@ -89,19 +99,23 @@ struct _GstObjectClass {
   void         (*object_saved)         (GstObject *object, xmlNodePtr parent);
 
   /* functions go here */
+  void         (*destroy)              (GstObject *object);
+
   xmlNodePtr   (*save_thyself)         (GstObject *object, xmlNodePtr parent);
   void         (*restore_thyself)      (GstObject *object, xmlNodePtr self);
 };
 
-#define GST_OBJECT_NAME(obj)           (const gchar*)(((GstObject *)(obj))->name)
-#define GST_OBJECT_PARENT(obj)         (((GstObject *)(obj))->parent)
-
-
-#define GST_FLAGS(obj)                 GTK_OBJECT_FLAGS(obj)
+#define GST_FLAGS(obj)                 (GST_OBJECT (obj)->flags)
 #define GST_FLAG_IS_SET(obj,flag)      (GST_FLAGS (obj) & (1<<(flag)))
 #define GST_FLAG_SET(obj,flag)         G_STMT_START{ (GST_FLAGS (obj) |= (1<<(flag))); }G_STMT_END
 #define GST_FLAG_UNSET(obj,flag)       G_STMT_START{ (GST_FLAGS (obj) &= ~(1<<(flag))); }G_STMT_END
 
+#define GST_OBJECT_NAME(obj)           (const gchar*)(((GstObject *)(obj))->name)
+#define GST_OBJECT_PARENT(obj)         (((GstObject *)(obj))->parent)
+
+#define GST_OBJECT_DESTROYED(obj)      (GST_FLAG_IS_SET (obj, GST_DESTROYED))
+#define GST_OBJECT_FLOATING(obj)       (GST_FLAG_IS_SET (obj, GST_FLOATING))
+
 /* object locking */
 #define GST_LOCK(obj)          (g_mutex_lock(GST_OBJECT(obj)->lock))
 #define GST_TRYLOCK(obj)       (g_mutex_trylock(GST_OBJECT(obj)->lock))
@@ -122,15 +136,17 @@ void              gst_object_set_parent           (GstObject *object,GstObject *parent);
 GstObject*     gst_object_get_parent           (GstObject *object);
 void           gst_object_unparent             (GstObject *object);
 
+gboolean       gst_object_check_uniqueness     (GList *list, const gchar *name);
+
 xmlNodePtr     gst_object_save_thyself         (GstObject *object, xmlNodePtr parent);
 
 /* refcounting */
-#define                gst_object_ref(object)          gtk_object_ref(GTK_OBJECT(object));
-#define                gst_object_unref(object)        gtk_object_unref(GTK_OBJECT(object));
-#define                gst_object_sink(object)         gtk_object_sink(GTK_OBJECT(object));
+GstObject *    gst_object_ref                  (GstObject *object);            
+void           gst_object_unref                (GstObject *object);            
+void           gst_object_sink                 (GstObject *object);            
 
 /* destroying an object */
-#define                gst_object_destroy(object)      gtk_object_destroy(GTK_OBJECT(object))
+void           gst_object_destroy              (GstObject *object);            
 
 /* printing out the 'path' of the object */
 gchar *                gst_object_get_path_string      (GstObject *object);
index 48bd1e3..69913d2 100644 (file)
@@ -27,6 +27,7 @@
 #include "gstelement.h"
 #include "gsttype.h"
 #include "gstbin.h"
+#include "gstscheduler.h"
 
 
 /***** Start with the base GstPad class *****/
@@ -78,6 +79,9 @@ gst_pad_init (GstPad *pad)
 enum {
   REAL_SET_ACTIVE,
   REAL_CAPS_CHANGED,
+  REAL_CAPS_NEGO_FAILED,
+  REAL_CONNECTED,
+  REAL_DISCONNECTED,
   /* FILL ME */
   REAL_LAST_SIGNAL
 };
@@ -97,7 +101,6 @@ static void          gst_real_pad_get_arg            (GtkObject *object,GtkArg *arg,guint id);
 static void            gst_real_pad_destroy            (GtkObject *object);
 
 static void            gst_pad_push_func               (GstPad *pad, GstBuffer *buf);
-static gboolean                gst_pad_eos_func                (GstPad *pad);
 
 
 static GstPad *real_pad_parent_class = NULL;
@@ -144,16 +147,31 @@ gst_real_pad_class_init (GstRealPadClass *klass)
                     GTK_SIGNAL_OFFSET (GstRealPadClass, caps_changed),
                     gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
                     GTK_TYPE_POINTER);
+  gst_real_pad_signals[REAL_CAPS_NEGO_FAILED] =
+    gtk_signal_new ("caps_nego_failed", GTK_RUN_LAST, gtkobject_class->type,
+                    GTK_SIGNAL_OFFSET (GstRealPadClass, caps_nego_failed),
+                    gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
+                    GTK_TYPE_POINTER);
+  gst_real_pad_signals[REAL_CONNECTED] =
+    gtk_signal_new ("connected", GTK_RUN_LAST, gtkobject_class->type,
+                    GTK_SIGNAL_OFFSET (GstRealPadClass, connected),
+                    gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
+                    GTK_TYPE_POINTER);
+  gst_real_pad_signals[REAL_DISCONNECTED] =
+    gtk_signal_new ("disconnected", GTK_RUN_LAST, gtkobject_class->type,
+                    GTK_SIGNAL_OFFSET (GstRealPadClass, disconnected),
+                    gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
+                    GTK_TYPE_POINTER);
   gtk_object_class_add_signals (gtkobject_class, gst_real_pad_signals, REAL_LAST_SIGNAL);
 
   gtk_object_add_arg_type ("GstRealPad::active", GTK_TYPE_BOOL,
                            GTK_ARG_READWRITE, REAL_ARG_ACTIVE);
 
-  gtkobject_class->destroy = gst_real_pad_destroy;
-  gtkobject_class->set_arg = gst_real_pad_set_arg;
-  gtkobject_class->get_arg = gst_real_pad_get_arg;
+  gtkobject_class->destroy  = GST_DEBUG_FUNCPTR(gst_real_pad_destroy);
+  gtkobject_class->set_arg  = GST_DEBUG_FUNCPTR(gst_real_pad_set_arg);
+  gtkobject_class->get_arg  = GST_DEBUG_FUNCPTR(gst_real_pad_get_arg);
 
-  gstobject_class->save_thyself = gst_pad_save_thyself;
+  gstobject_class->save_thyself = GST_DEBUG_FUNCPTR(gst_pad_save_thyself);
   gstobject_class->path_string_separator = ".";
 }
 
@@ -167,7 +185,7 @@ gst_real_pad_init (GstRealPad *pad)
   pad->getfunc = NULL;
   pad->getregionfunc = NULL;
   pad->qosfunc = NULL;
-  pad->eosfunc = gst_pad_eos_func;
+  pad->eosfunc = GST_DEBUG_FUNCPTR(gst_pad_eos_func);
 
   pad->pushfunc = GST_DEBUG_FUNCPTR(gst_pad_push_func);
   pad->pullfunc = NULL;
@@ -260,6 +278,8 @@ gst_pad_new_from_template (GstPadTemplate *templ,
   g_return_val_if_fail (templ != NULL, NULL);
 
   pad = gst_pad_new (name, templ->direction);
+  gst_object_ref (GST_OBJECT (templ));
+  gst_object_sink (GST_OBJECT (templ));
   GST_PAD_PADTEMPLATE(pad) = templ;
 
   return pad;
@@ -330,8 +350,8 @@ void gst_pad_set_chain_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_CHAINFUNC(pad) = chain;
-  GST_DEBUG (0,"chainfunc for %s:%s(@%p) at %p is set to %p\n",
-             GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_CHAINFUNC(pad),chain);
+  GST_DEBUG (GST_CAT_PADS,"chainfunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(chain));
 }
 
 /**
@@ -349,8 +369,8 @@ gst_pad_set_get_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_GETFUNC(pad) = get;
-  GST_DEBUG (0,"getfunc for %s:%s(@%p) at %p is set to %p\n",
-             GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_GETFUNC(pad),get);
+  GST_DEBUG (GST_CAT_PADS,"getfunc for %s:%s  set to %s\n",
+             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(get));
 }
 
 /**
@@ -368,8 +388,8 @@ gst_pad_set_getregion_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_GETREGIONFUNC(pad) = getregion;
-  GST_DEBUG (0,"getregionfunc for %s:%s(@%p) at %p is set to %p\n",
-             GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_GETREGIONFUNC(pad),getregion);
+  GST_DEBUG (GST_CAT_PADS,"getregionfunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(getregion));
 }
 
 /**
@@ -387,8 +407,8 @@ gst_pad_set_qos_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_QOSFUNC(pad) = qos;
-  GST_DEBUG (0,"qosfunc for %s:%s(@%p) at %p is set to %p\n",
-             GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_QOSFUNC(pad),qos);
+  GST_DEBUG (GST_CAT_PADS,"qosfunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(qos));
 }
 
 /**
@@ -406,8 +426,8 @@ gst_pad_set_eos_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_EOSFUNC(pad) = eos;
-  GST_DEBUG (0,"eosfunc for %s:%s(@%p) at %p is set to %p\n",
-             GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_EOSFUNC(pad),eos);
+  GST_DEBUG (GST_CAT_PADS,"eosfunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(eos));
 }
 
 /**
@@ -425,11 +445,10 @@ gst_pad_set_negotiate_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_NEGOTIATEFUNC(pad) = nego;
-  GST_DEBUG (0,"negotiatefunc for %s:%s(@%p) at %p is set to %p\n",
-             GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_NEGOTIATEFUNC(pad),nego);
+  GST_DEBUG (GST_CAT_PADS,"negotiatefunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(nego));
 }
 
-
 /**
  * gst_pad_set_newcaps_function:
  * @pad: the pad to set the newcaps function for
@@ -445,8 +464,8 @@ gst_pad_set_newcaps_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_NEWCAPSFUNC (pad) = newcaps;
-  GST_DEBUG (0,"newcapsfunc for %s:%s(@%p) at %p is set to %p\n",
-             GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_NEWCAPSFUNC(pad),newcaps);
+  GST_DEBUG (GST_CAT_PADS,"newcapsfunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(newcaps));
 }
 
 /**
@@ -464,18 +483,19 @@ gst_pad_set_bufferpool_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_BUFFERPOOLFUNC (pad) = bufpool;
-  GST_DEBUG (0,"bufferpoolfunc for %s:%s(@%p) at %p is set to %p\n",
-             GST_DEBUG_PAD_NAME (pad), pad, &GST_RPAD_BUFFERPOOLFUNC (pad), bufpool);
+  GST_DEBUG (GST_CAT_PADS,"bufferpoolfunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME(bufpool));
 }
 
 static void
 gst_pad_push_func(GstPad *pad, GstBuffer *buf)
 {
   if (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)) != NULL) {
-    GST_DEBUG (0,"calling chain function\n");
+    GST_DEBUG (GST_CAT_DATAFLOW,"calling chain function %s\n",
+               GST_DEBUG_FUNCPTR_NAME(GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad))));
     (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)))(pad,buf);
   } else {
-    GST_DEBUG (0,"got a problem here: default pad_push handler in place, no chain function\n");
+    GST_DEBUG (GST_CAT_DATAFLOW,"got a problem here: default pad_push handler in place, no chain function\n");
   }
 }
 
@@ -495,7 +515,7 @@ gst_pad_handle_qos(GstPad *pad,
   GList *pads;
   GstPad *target_pad;
 
-  GST_DEBUG (0,"gst_pad_handle_qos(\"%s\",%08ld)\n", GST_OBJECT_NAME (GST_PAD_PARENT (pad)),qos_message);
+  GST_DEBUG (GST_CAT_PADS,"gst_pad_handle_qos(\"%s\",%08ld)\n", GST_OBJECT_NAME (GST_PAD_PARENT (pad)),qos_message);
 
   if (GST_RPAD_QOSFUNC(pad)) {
     (GST_RPAD_QOSFUNC(pad)) (pad,qos_message);
@@ -503,7 +523,7 @@ gst_pad_handle_qos(GstPad *pad,
     element = GST_ELEMENT (GST_PAD_PARENT(GST_RPAD_PEER(pad)));
 
     pads = element->pads;
-    GST_DEBUG (0,"gst_pad_handle_qos recurse(\"%s\",%08ld)\n", GST_ELEMENT_NAME (element), qos_message);
+    GST_DEBUG (GST_CAT_PADS,"gst_pad_handle_qos recurse(\"%s\",%08ld)\n", GST_ELEMENT_NAME (element), qos_message);
     while (pads) {
       target_pad = GST_PAD (pads->data);
       if (GST_RPAD_DIRECTION(target_pad) == GST_PAD_SINK) {
@@ -535,6 +555,9 @@ gst_pad_disconnect (GstPad *srcpad,
   g_return_if_fail (sinkpad != NULL);
   g_return_if_fail (GST_IS_PAD (sinkpad));
 
+  GST_INFO (GST_CAT_ELEMENT_PADS, "disconnecting %s:%s(%p) and %s:%s(%p)",
+            GST_DEBUG_PAD_NAME(srcpad), srcpad, GST_DEBUG_PAD_NAME(sinkpad), sinkpad);
+
   // now we need to deal with the real/ghost stuff
   realsrc = GST_PAD_REALIZE(srcpad);
   realsink = GST_PAD_REALIZE(sinkpad);
@@ -542,6 +565,14 @@ gst_pad_disconnect (GstPad *srcpad,
   g_return_if_fail (GST_RPAD_PEER(realsrc) != NULL);
   g_return_if_fail (GST_RPAD_PEER(realsink) != NULL);
 
+  if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) &&
+      (GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) {
+    GstRealPad *temppad;
+
+    temppad = realsrc;
+    realsrc = realsink;
+    realsink = temppad;
+  }
   g_return_if_fail ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) &&
                     (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK));
 
@@ -549,6 +580,16 @@ gst_pad_disconnect (GstPad *srcpad,
   GST_RPAD_PEER(realsrc) = NULL;
   GST_RPAD_PEER(realsink) = NULL;
 
+  /* fire off a signal to each of the pads telling them that they've been disconnected */
+  gtk_signal_emit(GTK_OBJECT(realsrc), gst_real_pad_signals[REAL_DISCONNECTED], realsink);
+  gtk_signal_emit(GTK_OBJECT(realsink), gst_real_pad_signals[REAL_DISCONNECTED], realsrc);
+
+  // now tell the scheduler
+  if (realsrc->sched)
+    GST_SCHEDULE_PAD_DISCONNECT (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink);
+//  if (realsink->sched)
+//    GST_SCHEDULE_PAD_DISCONNECT (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink);
+
   GST_INFO (GST_CAT_ELEMENT_PADS, "disconnected %s:%s and %s:%s",
             GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
 }
@@ -567,7 +608,6 @@ gst_pad_connect (GstPad *srcpad,
                 GstPad *sinkpad)
 {
   GstRealPad *realsrc, *realsink;
-  GstRealPad *temppad;
   gboolean negotiated = FALSE;
 
   /* generic checks */
@@ -576,49 +616,69 @@ gst_pad_connect (GstPad *srcpad,
   g_return_val_if_fail(sinkpad != NULL, FALSE);
   g_return_val_if_fail(GST_IS_PAD(sinkpad), FALSE);
 
-  GST_INFO (GST_CAT_ELEMENT_PADS, "about to connect %s:%s and %s:%s",
+  GST_INFO (GST_CAT_PADS, "connecting %s:%s and %s:%s",
             GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
 
   // now we need to deal with the real/ghost stuff
   realsrc = GST_PAD_REALIZE(srcpad);
   realsink = GST_PAD_REALIZE(sinkpad);
 
+  if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad))
+    GST_INFO (GST_CAT_PADS, "*actually* connecting %s:%s and %s:%s",
+              GST_DEBUG_PAD_NAME(realsrc), GST_DEBUG_PAD_NAME(realsink));
+
   g_return_val_if_fail(GST_RPAD_PEER(realsrc) == NULL, FALSE);
   g_return_val_if_fail(GST_RPAD_PEER(realsink) == NULL, FALSE);
 
   /* check for reversed directions and swap if necessary */
   if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) &&
       (GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) {
+    GstRealPad *temppad;
+
     temppad = realsrc;
     realsrc = realsink;
     realsink = temppad;
   }
   g_return_val_if_fail((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) &&
-                   (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK), FALSE);
+                       (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK), FALSE);
 
 
   /* first set peers */
   GST_RPAD_PEER(realsrc) = realsink;
   GST_RPAD_PEER(realsink) = realsrc;
 
-  /* FIXME: set connected flag */
-
-  GST_INFO (GST_CAT_ELEMENT_PADS, "connected %s:%s and %s:%s",
-            GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
-
   if (GST_PAD_CAPS (srcpad)) {
+    GST_DEBUG(GST_CAT_PADS, "renegotiation from srcpad\n");
     negotiated = gst_pad_renegotiate (srcpad);
   }
   else if (GST_PAD_CAPS (sinkpad)) {
+    GST_DEBUG(GST_CAT_PADS, "renegotiation from sinkpad\n");
     negotiated = gst_pad_renegotiate (sinkpad);
   }
-  else 
+  else {
+    GST_DEBUG(GST_CAT_PADS, "not renegotiating connection\n");
     negotiated = TRUE;
+  }
 
   if (!negotiated) {
+    GST_INFO(GST_CAT_PADS, "pads %s:%s and %s:%s failed to negotiate, disconnecting",
+             GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
     gst_pad_disconnect (GST_PAD (realsrc), GST_PAD (realsink));
     return FALSE;
   }
+
+  /* fire off a signal to each of the pads telling them that they've been connected */
+  gtk_signal_emit(GTK_OBJECT(realsrc), gst_real_pad_signals[REAL_CONNECTED], realsink);
+  gtk_signal_emit(GTK_OBJECT(realsink), gst_real_pad_signals[REAL_CONNECTED], realsrc);
+
+  // now tell the scheduler(s)
+  if (realsrc->sched)
+    GST_SCHEDULE_PAD_CONNECT (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink);
+  else if (realsink->sched)
+    GST_SCHEDULE_PAD_CONNECT (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink);
+
+  GST_INFO (GST_CAT_PADS, "connected %s:%s and %s:%s",
+            GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
   return TRUE;
 }
 
@@ -668,13 +728,31 @@ gst_pad_get_padtemplate (GstPad *pad)
  *
  * Returns: the parent object
  */
-GstObject*
+GstElement*
 gst_pad_get_parent (GstPad *pad)
 {
   g_return_val_if_fail (pad != NULL, NULL);
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
-  return GST_OBJECT_PARENT (pad);
+  return GST_PAD_PARENT (pad);
+}
+
+void
+gst_pad_set_sched (GstPad *pad, GstSchedule *sched)
+{
+  g_return_if_fail (pad != NULL);
+  g_return_if_fail (GST_IS_PAD (pad));
+
+  GST_RPAD_SCHED(pad) = sched;
+}
+
+GstSchedule*
+gst_pad_get_sched (GstPad *pad)
+{
+  g_return_val_if_fail (pad != NULL, NULL);
+  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+
+  return GST_RPAD_SCHED(pad);
 }
 
 /**
@@ -687,7 +765,7 @@ gst_pad_get_parent (GstPad *pad)
  *
  * Returns: the parent object
  */
-GstObject*
+GstElement*
 gst_pad_get_real_parent (GstPad *pad)
 {
   g_return_val_if_fail (pad != NULL, NULL);
@@ -892,7 +970,7 @@ gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
     }
   }
   else {
-    GST_DEBUG (0,"gstpad: could not check capabilities of pads (%s:%s) and (%s:%s) %p %p\n",
+    GST_DEBUG (GST_CAT_PADS,"could not check capabilities of pads (%s:%s) and (%s:%s) %p %p\n",
                    GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad), 
                    GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad));
     return TRUE;
@@ -940,25 +1018,51 @@ gst_pad_get_bufferpool (GstPad *pad)
   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
 
   if (peer->bufferpoolfunc) {
-    GST_DEBUG (0,"calling bufferpoolfunc &%s (@%p) of peer pad %s:%s\n",
+    GST_DEBUG (GST_CAT_PADS,"calling bufferpoolfunc &%s (@%p) of peer pad %s:%s\n",
       GST_DEBUG_FUNCPTR_NAME(peer->bufferpoolfunc),&peer->bufferpoolfunc,GST_DEBUG_PAD_NAME(((GstPad*)peer)));
     return (peer->bufferpoolfunc)(((GstPad*)peer));
   } else {
-    GST_DEBUG (0,"no bufferpoolfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->bufferpoolfunc);
+    GST_DEBUG (GST_CAT_PADS,"no bufferpoolfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->bufferpoolfunc);
     return NULL;
   }
 }
 
-
-// FIXME this needs to be rethought soon
 static void
 gst_real_pad_destroy (GtkObject *object)
 {
   GstPad *pad = GST_PAD (object);
 
-//  g_print("in gst_pad_real_destroy()\n");
+  GST_DEBUG (GST_CAT_REFCOUNTING, "destroy %s:%s\n", GST_DEBUG_PAD_NAME(pad));
+
+  if (GST_PAD (pad)->padtemplate)
+    gst_object_unref (GST_OBJECT (GST_PAD (pad)->padtemplate));
 
-  g_list_free (GST_REAL_PAD(pad)->ghostpads);
+  if (GST_PAD_PEER (pad))
+    gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
+
+  if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad)))
+    gst_element_remove_pad (GST_ELEMENT (GST_OBJECT_PARENT (pad)), pad);
+
+  // FIXME we should destroy the ghostpads, because they are nothing without the real pad
+  if (GST_REAL_PAD (pad)->ghostpads) {
+    GList *orig, *ghostpads;
+
+    orig = ghostpads = g_list_copy (GST_REAL_PAD (pad)->ghostpads);
+
+    while (ghostpads) {
+      GstPad *ghostpad = GST_PAD (ghostpads->data);
+
+      if (GST_IS_ELEMENT (GST_OBJECT_PARENT (ghostpad)))
+        gst_element_remove_pad (GST_ELEMENT (GST_OBJECT_PARENT (ghostpad)), ghostpad);
+
+      ghostpads = g_list_next (ghostpads);
+    }
+    g_list_free (orig);
+    g_list_free (GST_REAL_PAD(pad)->ghostpads);
+  }
+
+  if (GTK_OBJECT_CLASS (real_pad_parent_class)->destroy)
+    GTK_OBJECT_CLASS (real_pad_parent_class)->destroy (object);
 }
 
 
@@ -1170,9 +1274,22 @@ gst_pad_renegotiate (GstPad *pad)
   
   result = gst_pad_renegotiate_func (GST_PAD (currentpad), &data1, GST_PAD (otherpad), &data2, &newcaps);
 
+  if (!result) {
+    GST_DEBUG (GST_CAT_NEGOTIATION, "firing caps_nego_failed signal on %s:%s and %s:%s to give it a chance to succeed\n",
+               GST_DEBUG_PAD_NAME(currentpad),GST_DEBUG_PAD_NAME(otherpad));
+    gtk_signal_emit (GTK_OBJECT(currentpad), 
+                     gst_real_pad_signals[REAL_CAPS_NEGO_FAILED],&result);
+    gtk_signal_emit (GTK_OBJECT(otherpad), 
+                     gst_real_pad_signals[REAL_CAPS_NEGO_FAILED],&result);
+    if (result)
+      GST_DEBUG (GST_CAT_NEGOTIATION, "caps_nego_failed handler claims success at renego, believing\n");
+  }
+
   if (result) {
     GST_DEBUG (GST_CAT_NEGOTIATION, "pads aggreed on caps :)\n");
 
+  newcaps = GST_PAD_CAPS (pad);
+
     /* here we have some sort of aggreement of the caps */
     GST_PAD_CAPS (currentpad) = gst_caps_ref (newcaps);
     if (GST_RPAD_NEWCAPSFUNC (currentpad))
@@ -1181,6 +1298,13 @@ gst_pad_renegotiate (GstPad *pad)
     GST_PAD_CAPS (otherpad) = gst_caps_ref (newcaps);
     if (GST_RPAD_NEWCAPSFUNC (otherpad))
       GST_RPAD_NEWCAPSFUNC (otherpad) (GST_PAD (otherpad), newcaps);
+
+    GST_DEBUG (GST_CAT_NEGOTIATION, "firing caps_changed signal on %s:%s and %s:%s\n",
+               GST_DEBUG_PAD_NAME(currentpad),GST_DEBUG_PAD_NAME(otherpad));
+    gtk_signal_emit (GTK_OBJECT(currentpad), 
+                     gst_real_pad_signals[REAL_CAPS_CHANGED],GST_PAD_CAPS(currentpad));
+    gtk_signal_emit (GTK_OBJECT(otherpad), 
+                     gst_real_pad_signals[REAL_CAPS_CHANGED],GST_PAD_CAPS(otherpad));
   }
 
   return result;
@@ -1313,16 +1437,16 @@ gst_pad_push (GstPad *pad, GstBuffer *buf)
 {
   GstRealPad *peer = GST_RPAD_PEER (pad);
 
-  g_return_if_fail (peer != NULL);
-  
   GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
+
+  g_return_if_fail (peer != NULL);  
   
   if (peer->pushfunc) {
-    GST_DEBUG (0, "calling pushfunc &%s of peer pad %s:%s\n",
+    GST_DEBUG (GST_CAT_DATAFLOW, "calling pushfunc &%s of peer pad %s:%s\n",
           GST_DEBUG_FUNCPTR_NAME (peer->pushfunc), GST_DEBUG_PAD_NAME (((GstPad*)peer)));
     (peer->pushfunc) (((GstPad*)peer), buf);
   } else
-    GST_DEBUG (0, "no pushfunc\n");
+    GST_DEBUG (GST_CAT_DATAFLOW, "no pushfunc\n");
 }
 #endif
 
@@ -1340,16 +1464,16 @@ gst_pad_pull (GstPad *pad)
 {
   GstRealPad *peer = GST_RPAD_PEER(pad);
   
-  g_return_val_if_fail (peer != NULL, NULL);
-
   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
 
+  g_return_val_if_fail (peer != NULL, NULL);
+
   if (peer->pullfunc) {
-    GST_DEBUG (0,"calling pullfunc &%s (@%p) of peer pad %s:%s\n",
-      GST_DEBUG_FUNCPTR_NAME(peer->pullfunc),&peer->pullfunc,GST_DEBUG_PAD_NAME(((GstPad*)peer)));
+    GST_DEBUG (GST_CAT_DATAFLOW,"calling pullfunc %s of peer pad %s:%s\n",
+      GST_DEBUG_FUNCPTR_NAME(peer->pullfunc),GST_DEBUG_PAD_NAME(peer));
     return (peer->pullfunc)(((GstPad*)peer));
   } else {
-    GST_DEBUG (0,"no pullfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->pullfunc);
+    GST_DEBUG (GST_CAT_DATAFLOW,"no pullfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->pullfunc);
     return NULL;
   }
 }
@@ -1380,11 +1504,11 @@ gst_pad_pullregion (GstPad *pad, GstRegionType type, guint64 offset, guint64 len
   GST_DEBUG_ENTER("(%s:%s,%d,%lld,%lld)",GST_DEBUG_PAD_NAME(pad),type,offset,len);
 
   if (peer->pullregionfunc) {
-    GST_DEBUG (0,"calling pullregionfunc &%s of peer pad %s:%s\n",
+    GST_DEBUG (GST_CAT_DATAFLOW,"calling pullregionfunc &%s of peer pad %s:%s\n",
           GST_DEBUG_FUNCPTR_NAME(peer->pullregionfunc),GST_DEBUG_PAD_NAME(((GstPad*)peer)));
     return (peer->pullregionfunc)(((GstPad*)peer),type,offset,len);
   } else {
-    GST_DEBUG (0,"no pullregionfunc\n");
+    GST_DEBUG (GST_CAT_DATAFLOW,"no pullregionfunc\n");
     return NULL;
   }
 }
@@ -1528,7 +1652,7 @@ gst_padtemplate_save_thyself (GstPadTemplate *templ, xmlNodePtr parent)
   xmlNodePtr subtree;
   guchar *presence;
 
-  GST_DEBUG (0,"saving padtemplate %s\n", templ->name_template);
+  GST_DEBUG (GST_CAT_XML,"saving padtemplate %s\n", templ->name_template);
 
   xmlNewChild(parent,NULL,"nametemplate", templ->name_template);
   xmlNewChild(parent,NULL,"direction", (templ->direction == GST_PAD_SINK? "sink":"src"));
@@ -1616,7 +1740,7 @@ gst_padtemplate_load_thyself (xmlNodePtr parent)
 }
 
 
-static gboolean
+gboolean
 gst_pad_eos_func(GstPad *pad)
 {
   GstElement *element;
@@ -1649,6 +1773,8 @@ gst_pad_eos_func(GstPad *pad)
   GST_INFO (GST_CAT_PADS,"set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad));
   GST_FLAG_SET (pad, GST_PAD_EOS);
 
+  gst_element_set_state (GST_ELEMENT(GST_PAD_PARENT(pad)), GST_STATE_READY);
+
   return TRUE;
 }
 
@@ -1676,6 +1802,8 @@ gst_pad_set_eos(GstPad *pad)
   GST_INFO (GST_CAT_PADS,"set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad));
   GST_FLAG_SET (pad, GST_PAD_EOS);
 
+  gst_element_set_state (GST_ELEMENT(GST_PAD_PARENT(pad)), GST_STATE_READY);
+
   gst_element_signal_eos (GST_ELEMENT (GST_PAD_PARENT (pad)));
 
   return TRUE;
@@ -1783,7 +1911,7 @@ gst_ghost_pad_new (gchar *name,
 
   // FIXME need to ref the real pad here... ?
 
-  GST_DEBUG(0,"created ghost pad \"%s\"\n",name);
+  GST_DEBUG(GST_CAT_PADS,"created ghost pad \"%s\"\n",name);
 
   return GST_PAD(ghostpad);
 }
index 14731e0..c5d7224 100644 (file)
@@ -63,14 +63,14 @@ extern "C" {
 #define GST_IS_GHOST_PAD_CLASS(obj)    (GTK_CHECK_CLASS_TYPE ((klass), GST_TYPE_GHOST_PAD))
 
 
-typedef struct _GstPad GstPad;
-typedef struct _GstPadClass GstPadClass;
+//typedef struct _GstPad GstPad;
+//typedef struct _GstPadClass GstPadClass;
 typedef struct _GstRealPad GstRealPad;
 typedef struct _GstRealPadClass GstRealPadClass;
 typedef struct _GstGhostPad GstGhostPad;
 typedef struct _GstGhostPadClass GstGhostPadClass;
-typedef struct _GstPadTemplate GstPadTemplate;
-typedef struct _GstPadTemplateClass GstPadTemplateClass;
+//typedef struct _GstPadTemplate GstPadTemplate;
+//typedef struct _GstPadTemplateClass GstPadTemplateClass;
 
 
 typedef enum {
@@ -142,6 +142,8 @@ struct _GstRealPad {
   guint64                      offset;
   guint64                      len;
 
+  GstSchedule                  *sched;
+
   GstPadChainFunction          chainfunc;
   GstPadGetFunction            getfunc;
   GstPadGetRegionFunction      getregionfunc;
@@ -163,9 +165,13 @@ struct _GstRealPadClass {
   GstPadClass parent_class;
 
   /* signal callbacks */
-  void (*set_active)   (GstPad *pad, gboolean active);
-  void (*caps_changed) (GstPad *pad, GstCaps *newcaps);
-  void (*eos)          (GstPad *pad);
+  void (*set_active)           (GstPad *pad, gboolean active);
+  void (*caps_changed)         (GstPad *pad, GstCaps *newcaps);
+  void (*caps_nego_failed)     (GstPad *pad);
+  void (*connected)            (GstPad *pad, GstPad *peer);
+  void (*disconnected)         (GstPad *pad, GstPad *peer);
+
+  void (*eos)                  (GstPad *pad);
 };
 
 struct _GstGhostPad {
@@ -182,7 +188,7 @@ struct _GstGhostPadClass {
 /***** helper macros *****/
 /* GstPad */
 #define GST_PAD_NAME(pad)              (GST_OBJECT_NAME(pad))
-#define GST_PAD_PARENT(pad)            (GST_OBJECT_PARENT(pad))
+#define GST_PAD_PARENT(pad)            ((GstElement *)(GST_OBJECT_PARENT(pad)))
 #define GST_PAD_ELEMENT_PRIVATE(pad)   (((GstPad *)(pad))->element_private)
 #define GST_PAD_PADTEMPLATE(pad)       (((GstPad *)(pad))->padtemplate)
 
@@ -191,6 +197,7 @@ struct _GstGhostPadClass {
 #define GST_RPAD_CAPS(pad)             (((GstRealPad *)(pad))->caps)
 #define GST_RPAD_PEER(pad)             (((GstRealPad *)(pad))->peer)
 #define GST_RPAD_BUFPEN(pad)           (((GstRealPad *)(pad))->bufpen)
+#define GST_RPAD_SCHED(pad)            (((GstRealPad *)(pad))->sched)
 #define GST_RPAD_CHAINFUNC(pad)                (((GstRealPad *)(pad))->chainfunc)
 #define GST_RPAD_GETFUNC(pad)          (((GstRealPad *)(pad))->getfunc)
 #define GST_RPAD_GETREGIONFUNC(pad)    (((GstRealPad *)(pad))->getregionfunc)
@@ -312,8 +319,11 @@ void                       gst_pad_set_name                (GstPad *pad, const gchar *name);
 const gchar*           gst_pad_get_name                (GstPad *pad);
 
 void                   gst_pad_set_parent              (GstPad *pad, GstObject *parent);
-GstObject*             gst_pad_get_parent              (GstPad *pad);
-GstObject*             gst_pad_get_real_parent         (GstPad *pad);
+GstElement*            gst_pad_get_parent              (GstPad *pad);
+GstElement*            gst_pad_get_real_parent         (GstPad *pad);
+
+void                   gst_pad_set_sched               (GstPad *pad, GstSchedule *sched);
+GstSchedule*           gst_pad_get_sched               (GstPad *pad);
 
 void                   gst_pad_add_ghost_pad           (GstPad *pad, GstPad *ghostpad);
 void                   gst_pad_remove_ghost_pad        (GstPad *pad, GstPad *ghostpad);
@@ -356,6 +366,7 @@ NULL )
 #define                        gst_pad_eos(pad)                (GST_RPAD_EOSFUNC(GST_RPAD_PEER(pad))(GST_PAD(GST_RPAD_PEER(pad))))
 gboolean               gst_pad_set_eos                 (GstPad *pad);
 
+gboolean               gst_pad_eos_func                (GstPad *pad);
 void                   gst_pad_handle_qos              (GstPad *pad, glong qos_message);
 
 void                   gst_pad_load_and_connect        (xmlNodePtr self, GstObject *parent);
@@ -379,6 +390,7 @@ GstCaps*            gst_padtemplate_get_caps_by_name        (GstPadTemplate *templ, const gchar *
 xmlNodePtr             gst_padtemplate_save_thyself    (GstPadTemplate *templ, xmlNodePtr parent);
 GstPadTemplate*                gst_padtemplate_load_thyself    (xmlNodePtr parent);
 
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index f2772d4..f967add 100644 (file)
 #include "gst_private.h"
 
 #include "gstpipeline.h"
+#include "gstthread.h"
+#include "gstutils.h"
+#include "gsttype.h"
+#include "gstautoplug.h"
+#include "gstscheduler.h"
 
 
 GstElementDetails gst_pipeline_details = {
@@ -95,6 +100,10 @@ gst_pipeline_init (GstPipeline *pipeline)
 {
   // we're a manager by default
   GST_FLAG_SET (pipeline, GST_BIN_FLAG_MANAGER);
+
+  GST_ELEMENT_SCHED(pipeline) = gst_schedule_new(GST_ELEMENT(pipeline));
+  GST_DEBUG(GST_CAT_PIPELINE, "pipeline's scheduler is %p\n",GST_ELEMENT_SCHED(pipeline));
+//  gst_element_set_manager(GST_ELEMENT(pipeline),GST_ELEMENT(pipeline));
 }
 
 
@@ -107,16 +116,16 @@ gst_pipeline_init (GstPipeline *pipeline)
  * Returns: newly created GstPipeline
  */
 GstElement*
-gst_pipeline_new (const guchar *name)
+gst_pipeline_new (const guchar *name) 
 {
   return gst_elementfactory_make ("pipeline", name);
 }
 
-static void
-gst_pipeline_prepare (GstPipeline *pipeline)
+static void 
+gst_pipeline_prepare (GstPipeline *pipeline) 
 {
-  GST_DEBUG (0,"GstPipeline: preparing pipeline \"%s\" for playing\n",
-                 GST_ELEMENT_NAME(GST_ELEMENT(pipeline)));
+  GST_DEBUG (GST_CAT_PIPELINE,"preparing pipeline \"%s\" for playing (DEPRACATED!!)\n",
+             GST_ELEMENT_NAME(GST_ELEMENT(pipeline)));
 }
 
 static GstElementStateReturn
index 25d5a24..380b531 100644 (file)
@@ -53,19 +53,19 @@ gst_props_debug_entry (GstPropsEntry *entry)
 {
   switch (entry->propstype) {
     case GST_PROPS_INT_ID:
-      GST_DEBUG (0, "%d\n", entry->data.int_data);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%d\n", entry->data.int_data);
       break;
     case GST_PROPS_FOURCC_ID:
-      GST_DEBUG (0, "%4.4s\n", (gchar*)&entry->data.fourcc_data);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%4.4s\n", (gchar*)&entry->data.fourcc_data);
       break;
     case GST_PROPS_BOOL_ID:
-      GST_DEBUG (0, "%d\n", entry->data.bool_data);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%d\n", entry->data.bool_data);
       break;
     case GST_PROPS_STRING_ID:
-      GST_DEBUG (0, "%s\n", entry->data.string_data.string);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%s\n", entry->data.string_data.string);
       break;
     case GST_PROPS_INT_RANGE_ID:
-      GST_DEBUG (0, "%d-%d\n", entry->data.int_range_data.min,
+      GST_DEBUG (GST_CAT_PROPERTIES, "%d-%d\n", entry->data.int_range_data.min,
                      entry->data.int_range_data.max);
       break;
     default:
@@ -616,7 +616,7 @@ gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *
 static gboolean
 gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
 {
-  GST_DEBUG (0,"compare: %s %s\n", g_quark_to_string (entry1->propid),
+  GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s\n", g_quark_to_string (entry1->propid),
                             g_quark_to_string (entry2->propid));
   switch (entry1->propstype) {
     case GST_PROPS_LIST_ID:
@@ -674,10 +674,13 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry
       switch (entry2->propstype) {
        // b   <--->   a - d
         case GST_PROPS_INT_RANGE_ID:
+          GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?\n",entry2->data.int_range_data.min,
+                    entry1->data.int_data,entry2->data.int_range_data.max);
          return (entry2->data.int_range_data.min <= entry1->data.int_data &&
                  entry2->data.int_range_data.max >= entry1->data.int_data);
        // b   <--->   a
         case GST_PROPS_INT_ID:
+          GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?\n",entry1->data.int_data,entry2->data.int_data);
          return (entry2->data.int_data == entry1->data.int_data);
        // b   <--->   a,b,c
         case GST_PROPS_LIST_ID:
@@ -761,14 +764,14 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
     entry2 = (GstPropsEntry *)sinklist->data;
 
     while (entry1->propid < entry2->propid) {
-      GST_DEBUG (0,"source is more specific in \"%s\"\n", g_quark_to_string (entry1->propid));
+      GST_DEBUG (GST_CAT_PROPERTIES,"source is more specific in \"%s\"\n", g_quark_to_string (entry1->propid));
       more++;
       sourcelist = g_list_next (sourcelist);
       if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
       else goto end;
     }
     while (entry1->propid > entry2->propid) {
-      GST_DEBUG (0,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
+      GST_DEBUG (GST_CAT_PROPERTIES,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
       missing++;
       sinklist = g_list_next (sinklist);
       if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
@@ -777,7 +780,7 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
 
     if (!gst_props_entry_check_compatibility (entry1, entry2)) {
        compatible = FALSE;
-       GST_DEBUG (0, "%s are not compatible\n:",
+       GST_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: \n",
                   g_quark_to_string (entry1->propid));
        gst_props_debug_entry (entry1);
        gst_props_debug_entry (entry2);
@@ -790,7 +793,7 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
     GstPropsEntry *entry2;
     entry2 = (GstPropsEntry *)sinklist->data;
     missing++;
-    GST_DEBUG (0,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
+    GST_DEBUG (GST_CAT_PROPERTIES,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
   }
 end:
 
index 37a4f7f..755c8f8 100644 (file)
@@ -23,7 +23,7 @@
 //#define DEBUG_ENABLED
 //#define STATUS_ENABLED
 #ifdef STATUS_ENABLED
-#define STATUS(A) GST_DEBUG(0,A, gst_element_get_name(GST_ELEMENT(queue)))
+#define STATUS(A) GST_DEBUG(GST_CAT_DATAFLOW, A, GST_ELEMENT_NAME(queue))
 #else
 #define STATUS(A)
 #endif
@@ -34,6 +34,7 @@
 #include "gst_private.h"
 
 #include "gstqueue.h"
+#include "gstscheduler.h"
 
 GstElementDetails gst_queue_details = {
   "Queue",
@@ -47,15 +48,22 @@ GstElementDetails gst_queue_details = {
 
 /* Queue signals and args */
 enum {
-  /* FILL ME */
+  LOW_WATERMARK,
+  HIGH_WATERMARK,
   LAST_SIGNAL
 };
 
 enum {
   ARG_0,
+  ARG_LEVEL_BUFFERS,
+  ARG_LEVEL_BYTES,
+  ARG_LEVEL_TIME,
+  ARG_SIZE_BUFFERS,
+  ARG_SIZE_BYTES,
+  ARG_SIZE_TIME,
+  ARG_LEAKY,
   ARG_LEVEL,
   ARG_MAX_LEVEL,
-  ARG_BLOCK,
 };
 
 
@@ -76,6 +84,23 @@ static void                  gst_queue_flush         (GstQueue *queue);
 
 static GstElementStateReturn   gst_queue_change_state  (GstElement *element);
 
+  
+static GtkType
+queue_leaky_get_type(void) {
+  static GtkType queue_leaky_type = 0;
+  static GtkEnumValue queue_leaky[] = {
+    { GST_QUEUE_NO_LEAK, "0", "Not Leaky" },
+    { GST_QUEUE_LEAK_UPSTREAM, "1", "Leaky on Upstream" },
+    { GST_QUEUE_LEAK_DOWNSTREAM, "2", "Leaky on Downstream" },
+    { 0, NULL, NULL },
+  };
+  if (!queue_leaky_type) {
+    queue_leaky_type = gtk_type_register_enum("GstQueueLeaky", queue_leaky);
+  }
+  return queue_leaky_type;
+}
+#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type())
+
 
 static GstElementClass *parent_class = NULL;
 //static guint gst_queue_signals[LAST_SIGNAL] = { 0 };
@@ -111,12 +136,12 @@ gst_queue_class_init (GstQueueClass *klass)
 
   parent_class = gtk_type_class (GST_TYPE_ELEMENT);
 
+  gtk_object_add_arg_type ("GstQueue::leaky", GST_TYPE_QUEUE_LEAKY,
+                           GTK_ARG_READWRITE, ARG_LEAKY);
   gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT,
                            GTK_ARG_READABLE, ARG_LEVEL);
   gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT,
                            GTK_ARG_READWRITE, ARG_MAX_LEVEL);
-  gtk_object_add_arg_type ("GstQueue::block", GTK_TYPE_BOOL,
-                           GTK_ARG_READWRITE, ARG_BLOCK);
 
   gtkobject_class->set_arg = gst_queue_set_arg;
   gtkobject_class->get_arg = gst_queue_get_arg;
@@ -144,14 +169,15 @@ gst_queue_init (GstQueue *queue)
 
   queue->queue = NULL;
   queue->level_buffers = 0;
-  queue->max_buffers = 100;
-  queue->block = TRUE;
   queue->level_bytes = 0;
-  queue->size_buffers = 0;
-  queue->size_bytes = 0;
+  queue->level_time = 0LL;
+  queue->size_buffers = 100;           // 100 buffers
+  queue->size_bytes = 100 * 1024;      // 100KB
+  queue->size_time = 1000000000LL;     // 1sec
 
   queue->emptycond = g_cond_new ();
   queue->fullcond = g_cond_new ();
+  GST_DEBUG(GST_CAT_THREAD, "initialized queue's emptycond and fullcond\n");
 }
 
 static GstBufferPool*
@@ -206,10 +232,10 @@ gst_queue_handle_eos (GstPad *pad)
 
   queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
 
-  GST_DEBUG (0,"queue: %s received eos\n", GST_ELEMENT_NAME (queue));
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s received eos\n", GST_ELEMENT_NAME (queue));
 
   GST_LOCK (queue);
-  GST_DEBUG (0,"queue: %s has %d buffers left\n", GST_ELEMENT_NAME (queue),
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s has %d buffers left\n", GST_ELEMENT_NAME (queue),
                  queue->level_buffers);
 
   GST_FLAG_SET (pad, GST_PAD_EOS);
@@ -224,7 +250,7 @@ gst_queue_handle_eos (GstPad *pad)
 static void
 gst_queue_cleanup_buffers (gpointer data, const gpointer user_data)
 {
-  GST_DEBUG (0,"queue: %s cleaning buffer %p\n", (gchar *)user_data, data);
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s cleaning buffer %p\n", (gchar *)user_data, data);
 
   gst_buffer_unref (GST_BUFFER (data));
 }
@@ -257,45 +283,79 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf)
 
   /* we have to lock the queue since we span threads */
 
-  GST_DEBUG (0,"queue: try have queue lock\n");
+//  GST_DEBUG (GST_CAT_DATAFLOW,"trying to get lock on queue \"%s\"\n",name);
   GST_LOCK (queue);
-  GST_DEBUG (0,"queue: %s adding buffer %p %ld\n", name, buf, pthread_self ());
-  GST_DEBUG (0,"queue: have queue lock\n");
 
   if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) {
+    GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "buffer has FLUSH bit set, flushing queue\n");
     gst_queue_flush (queue);
   }
 
-  GST_DEBUG (0,"queue: %s: chain %d %p\n", name, queue->level_buffers, buf);
+  GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "adding buffer %p of size %d\n",buf,GST_BUFFER_SIZE(buf));
+
+  if (queue->level_buffers >= queue->size_buffers) {
+    // if this is a leaky queue...
+    if (queue->leaky) {
+      // if we leak on the upstream side, drop the current buffer
+      if (queue->leaky == GST_QUEUE_LEAK_UPSTREAM) {
+        GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on upstream end\n");
+        gst_buffer_unref(buf);
+        // now we have to clean up and exit right away
+        GST_UNLOCK (queue);
+        return;
+      }
+      // otherwise we have to push a buffer off the other end
+      else {
+        GSList *front;
+        GstBuffer *leakbuf;
+        GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end\n");
+        front = queue->queue;
+        leakbuf = (GstBuffer *)(front->data);
+        queue->level_buffers--;
+        queue->level_bytes -= GST_BUFFER_SIZE(leakbuf);
+        gst_buffer_unref(leakbuf);
+        queue->queue = g_slist_remove_link (queue->queue, front);
+        g_slist_free (front);
+      }
+    }
 
-  while (queue->level_buffers >= queue->max_buffers) {
-    GST_DEBUG (0,"queue: %s waiting %d\n", name, queue->level_buffers);
-    STATUS("%s: O\n");
-    //g_cond_timed_wait (queue->fullcond, queue->fulllock, queue->timeval);
-    //FIXME need to signal other thread in case signals got lost?
-    g_cond_signal (queue->emptycond);
-    g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock);
-    STATUS("%s: O+\n");
-    GST_DEBUG (0,"queue: %s waiting done %d\n", name, queue->level_buffers);
+    while (queue->level_buffers >= queue->size_buffers) {
+      // if there's a pending state change for this queue or its manager, switch
+      // back to iterator so bottom half of state change executes
+      if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
+//          GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
+GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->sinkpad))))) != 
+GST_STATE_NONE_PENDING)
+      {
+        GST_DEBUG(GST_CAT_DATAFLOW,"interrupted!!\n");
+        if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)
+          GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)\n");
+        if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
+          GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING\n");
+        GST_UNLOCK(queue);
+        cothread_switch(cothread_current_main());
+      }
+
+      GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for space, level is %d\n", queue->level_buffers);
+      g_cond_signal (queue->emptycond);
+      g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock);
+      GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "done waiting, level is now %d\n", queue->level_buffers);
+    }
   }
 
   /* put the buffer on the tail of the list */
   queue->queue = g_slist_append (queue->queue, buf);
-//  STATUS("%s: +\n");
-  GST_DEBUG (0,"(%s:%s)+ ",GST_DEBUG_PAD_NAME(pad));
-
-  /* if we were empty, but aren't any more, signal a condition */
-  tosignal = (queue->level_buffers >= 0);
   queue->level_buffers++;
+  queue->level_bytes += GST_BUFFER_SIZE(buf);
+//  GST_DEBUG (GST_CAT_DATAFLOW, "(%s:%s)+\n",GST_DEBUG_PAD_NAME(pad));
 
-  /* we can unlock now */
-  GST_DEBUG (0,"queue: %s chain %d end signal(%d,%p)\n", name, queue->level_buffers, tosignal, queue->emptycond);
-
-  if (tosignal) {
-//    STATUS("%s: >\n");
+  /* if we were empty, but aren't any more, signal a condition */
+  if (queue->level_buffers == 1)
+  {
+    GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling emptycond\n", name);
     g_cond_signal (queue->emptycond);
-//    STATUS("%s: >>\n");
   }
+
   GST_UNLOCK (queue);
 }
 
@@ -307,6 +367,8 @@ gst_queue_get (GstPad *pad)
   GSList *front;
   const guchar *name;
 
+  g_assert(pad != NULL);
+  g_assert(GST_IS_PAD(pad));
   g_return_val_if_fail (pad != NULL, NULL);
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
@@ -314,63 +376,74 @@ gst_queue_get (GstPad *pad)
   name = GST_ELEMENT_NAME (queue);
 
   /* have to lock for thread-safety */
-  GST_DEBUG (0,"queue: %s try have queue lock\n", name);
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s try have queue lock\n", name);
   GST_LOCK (queue);
-  GST_DEBUG (0,"queue: %s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
-  GST_DEBUG (0,"queue: %s have queue lock\n", name);
-
-  // we bail if there's nothing there
-  if (!queue->level_buffers && !queue->block) {
-    GST_UNLOCK(queue);
-    return NULL;
-  }
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s have queue lock\n", name);
 
   while (!queue->level_buffers) {
-    STATUS("queue: %s U released lock\n");
-    //g_cond_timed_wait (queue->emptycond, queue->emptylock, queue->timeval);
     if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) {
+      GST_DEBUG (GST_CAT_DATAFLOW, "%s U released lock\n", name);
+      GST_UNLOCK(queue);
       gst_pad_set_eos (queue->srcpad);
+      // this return NULL shouldn't hurt anything...
       return NULL;
     }
-    //FIXME need to signal other thread in case signals got lost?
+
+    // if there's a pending state change for this queue or its manager, switch
+    // back to iterator so bottom half of state change executes
+    if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
+//        GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
+GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->srcpad))))) != 
+GST_STATE_NONE_PENDING)
+    {
+      GST_DEBUG(GST_CAT_DATAFLOW,"interrupted!!\n");
+      if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)
+        GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)\n");
+      if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
+        GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING\n");
+      GST_UNLOCK(queue);
+      cothread_switch(cothread_current_main());
+    }
+
     g_cond_signal (queue->fullcond);
     g_cond_wait (queue->emptycond, GST_OBJECT(queue)->lock);
-//    STATUS("queue: %s U- getting lock\n");
   }
 
   front = queue->queue;
   buf = (GstBuffer *)(front->data);
-  GST_DEBUG (0,"retrieved buffer %p from queue\n",buf);
+  GST_DEBUG (GST_CAT_DATAFLOW,"retrieved buffer %p from queue\n",buf);
   queue->queue = g_slist_remove_link (queue->queue, front);
   g_slist_free (front);
 
-  queue->level_buffers--;
-//  STATUS("%s: -\n");
-  GST_DEBUG (0,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
-
-  if (queue->level_buffers < queue->max_buffers) {
-//    STATUS("%s: < \n");
+//  if (queue->level_buffers < queue->size_buffers)
+  if (queue->level_buffers == queue->size_buffers)
+  {
+    GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling fullcond\n", name);
     g_cond_signal (queue->fullcond);
-//    STATUS("%s: << \n");
   }
-  GST_UNLOCK(queue);
 
-//  GST_DEBUG (0,"queue: %s pushing %d %p \n", name, queue->level_buffers, buf);
-//  gst_pad_push (queue->srcpad, buf);
-//  GST_DEBUG (0,"queue: %s pushing %d done \n", name, queue->level_buffers);
+  queue->level_buffers--;
+  queue->level_bytes -= GST_BUFFER_SIZE(buf);
+  GST_DEBUG (GST_CAT_DATAFLOW,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
+
+  GST_UNLOCK(queue);
 
   return buf;
-  /* unlock now */
 }
 
 static GstElementStateReturn
 gst_queue_change_state (GstElement *element)
 {
   GstQueue *queue;
+  GstElementStateReturn ret;
   g_return_val_if_fail (GST_IS_QUEUE (element), GST_STATE_FAILURE);
 
   queue = GST_QUEUE (element);
-  GST_DEBUG (0,"gstqueue: state pending %d\n", GST_STATE_PENDING (element));
+
+  // lock the queue so another thread (not in sync with this thread's state)
+  // can't call this queue's _get (or whatever)
+  GST_LOCK (queue);
 
   /* if going down into NULL state, clear out buffers*/
   if (GST_STATE_PENDING (element) == GST_STATE_READY) {
@@ -380,9 +453,41 @@ gst_queue_change_state (GstElement *element)
 
   /* if we haven't failed already, give the parent class a chance to ;-) */
   if (GST_ELEMENT_CLASS (parent_class)->change_state)
-    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+  {
+    gboolean valid_handler = FALSE;
+    guint state_change_id = gtk_signal_lookup("state_change", GTK_OBJECT_TYPE(element));
+
+    // determine whether we need to block the parent (element) class'
+    // STATE_CHANGE signal so we can UNLOCK before returning.  we block
+    // it if we could find the state_change signal AND there's a signal
+    // handler attached to it.
+    //
+    // note: this assumes that change_state() *only* emits state_change signal.
+    // if element change_state() emits other signals, they need to be blocked
+    // as well.
+    if (state_change_id &&
+        gtk_signal_handler_pending(GTK_OBJECT(element), state_change_id, FALSE))
+      valid_handler = TRUE;
+    if (valid_handler)
+      gtk_signal_handler_block(GTK_OBJECT(element), state_change_id);
+
+    ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+    if (valid_handler)
+      gtk_signal_handler_unblock(GTK_OBJECT(element), state_change_id);
+
+    // UNLOCK, *then* emit signal (if there's one there)
+    GST_UNLOCK(queue);
+    if (valid_handler)
+      gtk_signal_emit(GTK_OBJECT (element), state_change_id, GST_STATE(element));
+  }
+  else
+  {
+    ret = GST_STATE_SUCCESS;
+    GST_UNLOCK(queue);
+  }
 
-  return GST_STATE_SUCCESS;
+  return ret;
 }
 
 
@@ -397,11 +502,11 @@ gst_queue_set_arg (GtkObject *object, GtkArg *arg, guint id)
   queue = GST_QUEUE (object);
 
   switch(id) {
-    case ARG_MAX_LEVEL:
-      queue->max_buffers = GTK_VALUE_INT (*arg);
+    case ARG_LEAKY:
+      queue->leaky = GTK_VALUE_INT (*arg);
       break;
-    case ARG_BLOCK:
-      queue->block = GTK_VALUE_BOOL (*arg);
+    case ARG_MAX_LEVEL:
+      queue->size_buffers = GTK_VALUE_INT (*arg);
       break;
     default:
       break;
@@ -419,14 +524,14 @@ gst_queue_get_arg (GtkObject *object, GtkArg *arg, guint id)
   queue = GST_QUEUE (object);
 
   switch (id) {
+    case ARG_LEAKY:
+      GTK_VALUE_INT (*arg) = queue->leaky;
+      break;
     case ARG_LEVEL:
       GTK_VALUE_INT (*arg) = queue->level_buffers;
       break;
     case ARG_MAX_LEVEL:
-      GTK_VALUE_INT (*arg) = queue->max_buffers;
-      break;
-    case ARG_BLOCK:
-      GTK_VALUE_BOOL (*arg) = queue->block;
+      GTK_VALUE_INT (*arg) = queue->size_buffers;
       break;
     default:
       arg->type = GTK_TYPE_INVALID;
index 6063467..085d5ac 100644 (file)
@@ -47,6 +47,12 @@ GstElementDetails gst_queue_details;
 #define GST_IS_QUEUE_CLASS(obj) \
   (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
 
+enum {
+  GST_QUEUE_NO_LEAK            = 0,
+  GST_QUEUE_LEAK_UPSTREAM      = 1,
+  GST_QUEUE_LEAK_DOWNSTREAM    = 2
+};
+
 typedef struct _GstQueue GstQueue;
 typedef struct _GstQueueClass GstQueueClass;
 
@@ -60,12 +66,16 @@ struct _GstQueue {
   GSList *queue;
 
   gint level_buffers;  /* number of buffers queued here */
-  gint max_buffers;    /* maximum number of buffers queued here */
-  gboolean block;      /* if set to FALSE, _get returns NULL if queue empty */
   gint level_bytes;    /* number of bytes queued here */
+  guint64 level_time;  /* amount of time queued here */
+
   gint size_buffers;   /* size of queue in buffers */
   gint size_bytes;     /* size of queue in bytes */
+  guint64 size_time;   /* size of queue in time */
 
+  gint leaky;          /* whether the queue is leaky, and if so at which end */
+
+//  GMutex *lock;      (optimization?)
   GCond *emptycond;
   GCond *fullcond;
 
@@ -74,6 +84,10 @@ struct _GstQueue {
 
 struct _GstQueueClass {
   GstElementClass parent_class;
+
+  /* signal callbacks */
+  void (*low_watermark)                (GstQueue *queue, gint level);
+  void (*high_watermark)       (GstQueue *queue, gint level);
 };
 
 GtkType gst_queue_get_type (void);
index e4e1d79..0795c18 100644 (file)
@@ -27,7 +27,7 @@
 
 
 static int
-gst_bin_loopfunc_wrapper (int argc,char *argv[])
+gst_schedule_loopfunc_wrapper (int argc,char *argv[])
 {
   GstElement *element = GST_ELEMENT (argv);
   G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element);
@@ -35,10 +35,10 @@ gst_bin_loopfunc_wrapper (int argc,char *argv[])
   GST_DEBUG_ENTER("(%d,'%s')",argc,name);
 
   do {
-    GST_DEBUG (0,"calling loopfunc %s for element %s\n",
-          GST_DEBUG_FUNCPTR_NAME (element->loopfunc),name);
+    GST_DEBUG (GST_CAT_DATAFLOW,"calling loopfunc %s for element %s\n",
+               GST_DEBUG_FUNCPTR_NAME (element->loopfunc),name);
     (element->loopfunc) (element);
-    GST_DEBUG (0,"element %s ended loop function\n", name);
+    GST_DEBUG (GST_CAT_DATAFLOW,"element %s ended loop function\n", name);
   } while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element));
   GST_FLAG_UNSET(element,GST_ELEMENT_COTHREAD_STOPPING);
 
@@ -47,7 +47,7 @@ gst_bin_loopfunc_wrapper (int argc,char *argv[])
 }
 
 static int
-gst_bin_chain_wrapper (int argc,char *argv[])
+gst_schedule_chain_wrapper (int argc,char *argv[])
 {
   GstElement *element = GST_ELEMENT (argv);
   G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element);
@@ -57,7 +57,8 @@ gst_bin_chain_wrapper (int argc,char *argv[])
   GstBuffer *buf;
 
   GST_DEBUG_ENTER("(\"%s\")",name);
-  GST_DEBUG (0,"stepping through pads\n");
+
+  GST_DEBUG (GST_CAT_DATAFLOW,"stepping through pads\n");
   do {
     pads = element->pads;
     while (pads) {
@@ -66,11 +67,11 @@ gst_bin_chain_wrapper (int argc,char *argv[])
       if (!GST_IS_REAL_PAD(pad)) continue;
       realpad = GST_REAL_PAD(pad);
       if (GST_RPAD_DIRECTION(realpad) == GST_PAD_SINK) {
-        GST_DEBUG (0,"pulling a buffer from %s:%s\n", name, GST_PAD_NAME (pad));
+        GST_DEBUG (GST_CAT_DATAFLOW,"pulling a buffer from %s:%s\n", name, GST_PAD_NAME (pad));
         buf = gst_pad_pull (pad);
-        GST_DEBUG (0,"calling chain function of %s:%s\n", name, GST_PAD_NAME (pad));
+        GST_DEBUG (GST_CAT_DATAFLOW,"calling chain function of %s:%s\n", name, GST_PAD_NAME (pad));
         if (buf) GST_RPAD_CHAINFUNC(realpad) (pad,buf);
-        GST_DEBUG (0,"calling chain function of %s:%s done\n", name, GST_PAD_NAME (pad));
+        GST_DEBUG (GST_CAT_DATAFLOW,"calling chain function of %s:%s done\n", name, GST_PAD_NAME (pad));
       }
     }
   } while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element));
@@ -81,7 +82,7 @@ gst_bin_chain_wrapper (int argc,char *argv[])
 }
 
 static int
-gst_bin_src_wrapper (int argc,char *argv[])
+gst_schedule_src_wrapper (int argc,char *argv[])
 {
   GstElement *element = GST_ELEMENT (argv);
   GList *pads;
@@ -98,7 +99,7 @@ gst_bin_src_wrapper (int argc,char *argv[])
       realpad = (GstRealPad*)(pads->data);
       pads = g_list_next(pads);
       if (GST_RPAD_DIRECTION(realpad) == GST_PAD_SRC) {
-        GST_DEBUG (0,"calling _getfunc for %s:%s\n",GST_DEBUG_PAD_NAME(realpad));
+        GST_DEBUG (GST_CAT_DATAFLOW,"calling _getfunc for %s:%s\n",GST_DEBUG_PAD_NAME(realpad));
         if (realpad->regiontype != GST_REGION_NONE) {
           g_return_val_if_fail (GST_RPAD_GETREGIONFUNC(realpad) != NULL, 0);
 //          if (GST_RPAD_GETREGIONFUNC(realpad) == NULL)
@@ -114,7 +115,7 @@ gst_bin_src_wrapper (int argc,char *argv[])
           buf = GST_RPAD_GETFUNC(realpad) ((GstPad*)realpad);
         }
 
-        GST_DEBUG (0,"calling gst_pad_push on pad %s:%s\n",GST_DEBUG_PAD_NAME(realpad));
+        GST_DEBUG (GST_CAT_DATAFLOW,"calling gst_pad_push on pad %s:%s\n",GST_DEBUG_PAD_NAME(realpad));
         if (buf) gst_pad_push ((GstPad*)realpad, buf);
       }
     }
@@ -126,40 +127,56 @@ gst_bin_src_wrapper (int argc,char *argv[])
 }
 
 static void
-gst_bin_pushfunc_proxy (GstPad *pad, GstBuffer *buf)
+gst_schedule_pushfunc_proxy (GstPad *pad, GstBuffer *buf)
 {
-  cothread_state *threadstate = GST_ELEMENT (GST_PAD_PARENT (pad))->threadstate;
+  GstRealPad *peer = GST_RPAD_PEER(pad);
+
   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
   GST_DEBUG (GST_CAT_DATAFLOW,"putting buffer %p in peer's pen\n",buf);
 
   // FIXME this should be bounded
   // loop until the bufferpen is empty so we can fill it up again
   while (GST_RPAD_BUFPEN(pad) != NULL) {
-    GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p to empty bufpen\n",threadstate);
-    cothread_switch (threadstate);
+    GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p to empty bufpen\n",
+               GST_ELEMENT (GST_PAD_PARENT (pad))->threadstate);
+    cothread_switch (GST_ELEMENT (GST_PAD_PARENT (pad))->threadstate);
+
+    // we may no longer be the same pad, check.
+    if (GST_RPAD_PEER(peer) != (GstRealPad *)pad) {
+      GST_DEBUG (GST_CAT_DATAFLOW, "new pad in mid-switch!\n");
+      pad = (GstPad *)GST_RPAD_PEER(peer);
+    }
   }
 
   // now fill the bufferpen and switch so it can be consumed
   GST_RPAD_BUFPEN(GST_RPAD_PEER(pad)) = buf;
-  GST_DEBUG (GST_CAT_DATAFLOW,"switching to %p (@%p)\n",threadstate,&(GST_ELEMENT(GST_PAD_PARENT(pad))->threadstate));
-  cothread_switch (threadstate);
+  GST_DEBUG (GST_CAT_DATAFLOW,"switching to %p\n",GST_ELEMENT (GST_PAD_PARENT (pad))->threadstate);
+  cothread_switch (GST_ELEMENT (GST_PAD_PARENT (pad))->threadstate);
 
   GST_DEBUG (GST_CAT_DATAFLOW,"done switching\n");
 }
 
 static GstBuffer*
-gst_bin_pullfunc_proxy (GstPad *pad)
+gst_schedule_pullfunc_proxy (GstPad *pad)
 {
   GstBuffer *buf;
+  GstRealPad *peer = GST_RPAD_PEER(pad);
 
-  cothread_state *threadstate = GST_ELEMENT(GST_PAD_PARENT(pad))->threadstate;
   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
 
   // FIXME this should be bounded
   // we will loop switching to the peer until it's filled up the bufferpen
   while (GST_RPAD_BUFPEN(pad) == NULL) {
-    GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p to fill bufpen\n",threadstate);
-    cothread_switch (threadstate);
+    GST_DEBUG (GST_CAT_DATAFLOW, "switching to \"%s\": %p to fill bufpen\n",
+               GST_ELEMENT_NAME(GST_ELEMENT(GST_PAD_PARENT(pad))),
+               GST_ELEMENT(GST_PAD_PARENT(pad))->threadstate);
+    cothread_switch (GST_ELEMENT(GST_PAD_PARENT(pad))->threadstate);
+
+    // we may no longer be the same pad, check.
+    if (GST_RPAD_PEER(peer) != (GstRealPad *)pad) {
+      GST_DEBUG (GST_CAT_DATAFLOW, "new pad in mid-switch!\n");
+      pad = (GstPad *)GST_RPAD_PEER(peer);
+    }
   }
   GST_DEBUG (GST_CAT_DATAFLOW,"done switching\n");
 
@@ -170,11 +187,11 @@ gst_bin_pullfunc_proxy (GstPad *pad)
 }
 
 static GstBuffer*
-gst_bin_pullregionfunc_proxy (GstPad *pad,GstRegionType type,guint64 offset,guint64 len)
+gst_schedule_pullregionfunc_proxy (GstPad *pad,GstRegionType type,guint64 offset,guint64 len)
 {
   GstBuffer *buf;
+  GstRealPad *peer = GST_RPAD_PEER(pad);
 
-  cothread_state *threadstate = GST_ELEMENT(GST_PAD_PARENT(pad))->threadstate;
   GST_DEBUG_ENTER("%s:%s,%d,%lld,%lld",GST_DEBUG_PAD_NAME(pad),type,offset,len);
 
   // put the region info into the pad
@@ -185,8 +202,15 @@ gst_bin_pullregionfunc_proxy (GstPad *pad,GstRegionType type,guint64 offset,guin
   // FIXME this should be bounded
   // we will loop switching to the peer until it's filled up the bufferpen
   while (GST_RPAD_BUFPEN(pad) == NULL) {
-    GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p to fill bufpen\n",threadstate);
-    cothread_switch (threadstate);
+    GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p to fill bufpen\n",
+               GST_ELEMENT(GST_PAD_PARENT(pad))->threadstate);
+    cothread_switch (GST_ELEMENT(GST_PAD_PARENT(pad))->threadstate);
+
+    // we may no longer be the same pad, check.
+    if (GST_RPAD_PEER(peer) != (GstRealPad *)pad) {
+      GST_DEBUG (GST_CAT_DATAFLOW, "new pad in mid-switch!\n");
+      pad = (GstPad *)GST_RPAD_PEER(peer);
+    }
   }
   GST_DEBUG (GST_CAT_DATAFLOW,"done switching\n");
 
@@ -198,18 +222,18 @@ gst_bin_pullregionfunc_proxy (GstPad *pad,GstRegionType type,guint64 offset,guin
 
 
 static void
-gst_schedule_cothreaded_chain (GstBin *bin, _GstBinChain *chain) {
+gst_schedule_cothreaded_chain (GstBin *bin, GstScheduleChain *chain) {
   GList *elements;
   GstElement *element;
   cothread_func wrapper_function;
   GList *pads;
   GstPad *pad;
 
-  GST_DEBUG (0,"chain is using cothreads\n");
+  GST_DEBUG (GST_CAT_SCHEDULING,"chain is using COTHREADS\n");
 
   // first create thread context
   if (bin->threadcontext == NULL) {
-    GST_DEBUG (0,"initializing cothread context\n");
+    GST_DEBUG (GST_CAT_SCHEDULING,"initializing cothread context\n");
     bin->threadcontext = cothread_init ();
   }
 
@@ -224,19 +248,19 @@ gst_schedule_cothreaded_chain (GstBin *bin, _GstBinChain *chain) {
 
     // if the element has a loopfunc...
     if (element->loopfunc != NULL) {
-      wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_loopfunc_wrapper);
-      GST_DEBUG (0,"\nelement '%s' is a loop-based\n",GST_ELEMENT_NAME(element));
+      wrapper_function = GST_DEBUG_FUNCPTR(gst_schedule_loopfunc_wrapper);
+      GST_DEBUG (GST_CAT_SCHEDULING,"element '%s' is a loop-based\n",GST_ELEMENT_NAME(element));
     } else {
       // otherwise we need to decide what kind of cothread
       // if it's not DECOUPLED, we decide based on whether it's a source or not
       if (!GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
         // if it doesn't have any sinks, it must be a source (duh)
         if (element->numsinkpads == 0) {
-          wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_src_wrapper);
-          GST_DEBUG (0,"\nelement '%s' is a source, using _src_wrapper\n",GST_ELEMENT_NAME(element));
+          wrapper_function = GST_DEBUG_FUNCPTR(gst_schedule_src_wrapper);
+          GST_DEBUG (GST_CAT_SCHEDULING,"element '%s' is a source, using _src_wrapper\n",GST_ELEMENT_NAME(element));
         } else {
-          wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_chain_wrapper);
-          GST_DEBUG (0,"\nelement '%s' is a filter, using _chain_wrapper\n",GST_ELEMENT_NAME(element));
+          wrapper_function = GST_DEBUG_FUNCPTR(gst_schedule_chain_wrapper);
+          GST_DEBUG (GST_CAT_SCHEDULING,"element '%s' is a filter, using _chain_wrapper\n",GST_ELEMENT_NAME(element));
         }
       }
     }
@@ -250,13 +274,15 @@ gst_schedule_cothreaded_chain (GstBin *bin, _GstBinChain *chain) {
 
       // if the element is DECOUPLED or outside the manager, we have to chain
       if ((wrapper_function == NULL) ||
-          (GST_ELEMENT (GST_PAD_PARENT (GST_PAD (GST_RPAD_PEER (pad))))->manager != GST_ELEMENT(bin))) {
+          (GST_RPAD_PEER(pad) &&
+           (GST_ELEMENT (GST_PAD_PARENT (GST_PAD (GST_RPAD_PEER (pad))))->sched != chain->sched))
+         ) {
         // set the chain proxies
         if (GST_RPAD_DIRECTION(pad) == GST_PAD_SINK) {
-          GST_DEBUG (0,"copying chain function into push proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
+          GST_DEBUG (GST_CAT_SCHEDULING,"copying chain function into push proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
           GST_RPAD_PUSHFUNC(pad) = GST_RPAD_CHAINFUNC(pad);
         } else {
-          GST_DEBUG (0,"copying get function into pull proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
+          GST_DEBUG (GST_CAT_SCHEDULING,"copying get function into pull proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
           GST_RPAD_PULLFUNC(pad) = GST_RPAD_GETFUNC(pad);
           GST_RPAD_PULLREGIONFUNC(pad) = GST_RPAD_GETREGIONFUNC(pad);
         }
@@ -264,12 +290,12 @@ gst_schedule_cothreaded_chain (GstBin *bin, _GstBinChain *chain) {
       // otherwise we really are a cothread
       } else {
         if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
-          GST_DEBUG (0,"setting cothreaded push proxy for sinkpad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
-          GST_RPAD_PUSHFUNC(pad) = GST_DEBUG_FUNCPTR(gst_bin_pushfunc_proxy);
+          GST_DEBUG (GST_CAT_SCHEDULING,"setting cothreaded push proxy for sinkpad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
+          GST_RPAD_PUSHFUNC(pad) = GST_DEBUG_FUNCPTR(gst_schedule_pushfunc_proxy);
         } else {
-          GST_DEBUG (0,"setting cothreaded pull proxy for srcpad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
-          GST_RPAD_PULLFUNC(pad) = GST_DEBUG_FUNCPTR(gst_bin_pullfunc_proxy);
-          GST_RPAD_PULLREGIONFUNC(pad) = GST_DEBUG_FUNCPTR(gst_bin_pullregionfunc_proxy);
+          GST_DEBUG (GST_CAT_SCHEDULING,"setting cothreaded pull proxy for srcpad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
+          GST_RPAD_PULLFUNC(pad) = GST_DEBUG_FUNCPTR(gst_schedule_pullfunc_proxy);
+          GST_RPAD_PULLREGIONFUNC(pad) = GST_DEBUG_FUNCPTR(gst_schedule_pullregionfunc_proxy);
         }
       }
     }
@@ -279,10 +305,10 @@ gst_schedule_cothreaded_chain (GstBin *bin, _GstBinChain *chain) {
       if (element->threadstate == NULL) {
         // FIXME handle cothread_create returning NULL
         element->threadstate = cothread_create (bin->threadcontext);
-        GST_DEBUG (0,"created cothread %p for '%s'\n",element->threadstate,GST_ELEMENT_NAME(element));
+        GST_DEBUG (GST_CAT_SCHEDULING,"created cothread %p for '%s'\n",element->threadstate,GST_ELEMENT_NAME(element));
       }
       cothread_setfunc (element->threadstate, wrapper_function, 0, (char **)element);
-      GST_DEBUG (0,"set wrapper function for '%s' to &%s\n",GST_ELEMENT_NAME(element),
+      GST_DEBUG (GST_CAT_SCHEDULING,"set wrapper function for '%s' to &%s\n",GST_ELEMENT_NAME(element),
             GST_DEBUG_FUNCPTR_NAME(wrapper_function));
     }
   }
@@ -295,7 +321,7 @@ gst_schedule_chained_chain (GstBin *bin, _GstBinChain *chain) {
   GList *pads;
   GstPad *pad;
 
-  GST_DEBUG (0,"chain entered\n");
+  GST_DEBUG (GST_CAT_SCHEDULING,"chain entered\n");
   // walk through all the elements
   elements = chain->elements;
   while (elements) {
@@ -310,10 +336,10 @@ gst_schedule_chained_chain (GstBin *bin, _GstBinChain *chain) {
       if (!GST_IS_REAL_PAD(pad)) continue;
 
       if (GST_RPAD_DIRECTION(pad) == GST_PAD_SINK) {
-        GST_DEBUG (0,"copying chain function into push proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
+        GST_DEBUG (GST_CAT_SCHEDULING,"copying chain function into push proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
         GST_RPAD_PUSHFUNC(pad) = GST_RPAD_CHAINFUNC(pad);
       } else {
-        GST_DEBUG (0,"copying get function into pull proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
+        GST_DEBUG (GST_CAT_SCHEDULING,"copying get function into pull proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
         GST_RPAD_PULLFUNC(pad) = GST_RPAD_GETFUNC(pad);
         GST_RPAD_PULLREGIONFUNC(pad) = GST_RPAD_GETREGIONFUNC(pad);
       }
@@ -321,6 +347,7 @@ gst_schedule_chained_chain (GstBin *bin, _GstBinChain *chain) {
   }
 }
 
+/* depracated!! */
 static void
 gst_bin_schedule_cleanup (GstBin *bin)
 {
@@ -332,6 +359,7 @@ gst_bin_schedule_cleanup (GstBin *bin)
     chain = (_GstBinChain *)(chains->data);
     chains = g_list_next(chains);
 
+//    g_list_free(chain->disabled);
     g_list_free(chain->elements);
     g_list_free(chain->entries);
 
@@ -345,10 +373,11 @@ gst_bin_schedule_cleanup (GstBin *bin)
 static void
 gst_scheduler_handle_eos (GstElement *element, _GstBinChain *chain)
 {
-  GST_DEBUG (0,"chain removed from scheduler, EOS from element \"%s\"\n", GST_ELEMENT_NAME (element));
+  GST_DEBUG (GST_CAT_SCHEDULING,"chain removed from scheduler, EOS from element \"%s\"\n", GST_ELEMENT_NAME (element));
   chain->need_scheduling = FALSE;
 }
 
+/*
 void gst_bin_schedule_func(GstBin *bin) {
   GList *elements;
   GstElement *element;
@@ -357,14 +386,14 @@ void gst_bin_schedule_func(GstBin *bin) {
   GstPad *pad;
   GstElement *peerparent;
   GList *chains;
-  _GstBinChain *chain;
+  GstScheduleChain *chain;
 
   GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (GST_ELEMENT (bin)));
 
   gst_bin_schedule_cleanup(bin);
 
   // next we have to find all the separate scheduling chains
-  GST_DEBUG (0,"\nattempting to find scheduling chains...\n");
+  GST_DEBUG (GST_CAT_SCHEDULING,"attempting to find scheduling chains...\n");
   // first make a copy of the managed_elements we can mess with
   elements = g_list_copy (bin->managed_elements);
   // we have to repeat until the list is empty to get all chains
@@ -374,12 +403,12 @@ void gst_bin_schedule_func(GstBin *bin) {
     // if this is a DECOUPLED element
     if (GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
       // skip this element entirely
-      GST_DEBUG (0,"skipping '%s' because it's decoupled\n",GST_ELEMENT_NAME(element));
+      GST_DEBUG (GST_CAT_SCHEDULING,"skipping '%s' because it's decoupled\n",GST_ELEMENT_NAME(element));
       elements = g_list_next (elements);
       continue;
     }
 
-    GST_DEBUG (0,"starting with element '%s'\n",GST_ELEMENT_NAME(element));
+    GST_DEBUG (GST_CAT_SCHEDULING,"starting with element '%s'\n",GST_ELEMENT_NAME(element));
 
     // prime the pending list with the first element off the top
     pending = g_slist_prepend (NULL, element);
@@ -397,7 +426,7 @@ void gst_bin_schedule_func(GstBin *bin) {
       pending = g_slist_remove (pending, element);
 
       // add ourselves to the chain's list of elements
-      GST_DEBUG (0,"adding '%s' to chain\n",GST_ELEMENT_NAME(element));
+      GST_DEBUG (GST_CAT_SCHEDULING,"adding '%s' to chain\n",GST_ELEMENT_NAME(element));
       chain->elements = g_list_prepend (chain->elements, element);
       chain->num_elements++;
       gtk_signal_connect (GTK_OBJECT (element), "eos", gst_scheduler_handle_eos, chain);
@@ -412,13 +441,13 @@ void gst_bin_schedule_func(GstBin *bin) {
       if ((element->manager == GST_ELEMENT(bin)) &&
           !GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
         // remove ourselves from the outer list of all managed elements
-//        GST_DEBUG (0,"removing '%s' from list of possible elements\n",GST_ELEMENT_NAME(element));
+//        GST_DEBUG (GST_CAT_SCHEDULING,"removing '%s' from list of possible elements\n",GST_ELEMENT_NAME(element));
         elements = g_list_remove (elements, element);
 
         // if this element is a source, add it as an entry
         if (element->numsinkpads == 0) {
           chain->entries = g_list_prepend (chain->entries, element);
-          GST_DEBUG (0,"added '%s' as SRC entry into the chain\n",GST_ELEMENT_NAME(element));
+          GST_DEBUG (GST_CAT_SCHEDULING,"added '%s' as SRC entry into the chain\n",GST_ELEMENT_NAME(element));
         }
 
         // now we have to walk the pads to find peers
@@ -427,21 +456,22 @@ void gst_bin_schedule_func(GstBin *bin) {
           pad = GST_PAD (pads->data);
           pads = g_list_next (pads);
           if (!GST_IS_REAL_PAD(pad)) continue;
-          GST_DEBUG (0,"have pad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
+          GST_DEBUG (GST_CAT_SCHEDULING,"have pad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
 
+          if (GST_RPAD_PEER(pad) == NULL) continue;
          if (GST_RPAD_PEER(pad) == NULL) GST_ERROR(pad,"peer is null!");
           g_assert(GST_RPAD_PEER(pad) != NULL);
           g_assert(GST_PAD_PARENT (GST_PAD(GST_RPAD_PEER(pad))) != NULL);
 
           peerparent = GST_ELEMENT(GST_PAD_PARENT (GST_PAD(GST_RPAD_PEER(pad))));
 
-         GST_DEBUG (0,"peer pad %p\n", GST_RPAD_PEER(pad));
+         GST_DEBUG (GST_CAT_SCHEDULING,"peer pad %p\n", GST_RPAD_PEER(pad));
           // only bother with if the pad's peer's parent is this bin or it's DECOUPLED
           // only add it if it's in the list of un-visited elements still
           if ((g_list_find (elements, peerparent) != NULL) ||
               GST_FLAG_IS_SET (peerparent, GST_ELEMENT_DECOUPLED)) {
             // add the peer element to the pending list
-            GST_DEBUG (0,"adding '%s' to list of pending elements\n",
+            GST_DEBUG (GST_CAT_SCHEDULING,"adding '%s' to list of pending elements\n",
                        GST_ELEMENT_NAME(peerparent));
             pending = g_slist_prepend (pending, peerparent);
 
@@ -450,36 +480,36 @@ void gst_bin_schedule_func(GstBin *bin) {
                 (GST_FLAG_IS_SET (peerparent, GST_ELEMENT_DECOUPLED))) {
               chain->entries = g_list_prepend (chain->entries, peerparent);
               gtk_signal_connect (GTK_OBJECT (peerparent), "eos", gst_scheduler_handle_eos, chain);
-              GST_DEBUG (0,"added '%s' as DECOUPLED entry into the chain\n",GST_ELEMENT_NAME(peerparent));
+              GST_DEBUG (GST_CAT_SCHEDULING,"added '%s' as DECOUPLED entry into the chain\n",GST_ELEMENT_NAME(peerparent));
             }
           } else
-            GST_DEBUG (0,"element '%s' has already been dealt with\n",GST_ELEMENT_NAME(peerparent));
+            GST_DEBUG (GST_CAT_SCHEDULING,"element '%s' has already been dealt with\n",GST_ELEMENT_NAME(peerparent));
         }
       }
     } while (pending);
 
     // add the chain to the bin
-    GST_DEBUG (0,"have chain with %d elements: ",chain->num_elements);
+    GST_DEBUG (GST_CAT_SCHEDULING,"have chain with %d elements: ",chain->num_elements);
     { GList *elements = chain->elements;
       while (elements) {
         element = GST_ELEMENT (elements->data);
         elements = g_list_next(elements);
-        GST_DEBUG_NOPREFIX(0,"%s, ",GST_ELEMENT_NAME(element));
+        GST_DEBUG_NOPREFIX(GST_CAT_SCHEDULING,"%s, ",GST_ELEMENT_NAME(element));
       }
     }
-    GST_DEBUG_NOPREFIX(0,"\n");
+    GST_DEBUG_NOPREFIX(GST_CAT_DATAFLOW,"\n");
     bin->chains = g_list_prepend (bin->chains, chain);
     bin->num_chains++;
   }
   // free up the list in case it's full of DECOUPLED elements
   g_list_free (elements);
 
-  GST_DEBUG (0,"\nwe have %d chains to schedule\n",bin->num_chains);
+  GST_DEBUG (GST_CAT_SCHEDULING,"\nwe have %d chains to schedule\n",bin->num_chains);
 
   // now we have to go through all the chains and schedule them
   chains = bin->chains;
   while (chains) {
-    chain = (_GstBinChain *)(chains->data);
+    chain = (GstScheduleChain *)(chains->data);
     chains = g_list_next (chains);
 
     // schedule as appropriate
@@ -492,6 +522,7 @@ void gst_bin_schedule_func(GstBin *bin) {
 
   GST_DEBUG_LEAVE("(\"%s\")",GST_ELEMENT_NAME(GST_ELEMENT(bin)));
 }
+*/
 
 
 /*
@@ -744,4 +775,691 @@ void gst_bin_schedule_func(GstBin *bin) {
   }
 */
 
+static void 
+gst_schedule_lock_element (GstSchedule *sched,GstElement *element)
+{
+  cothread_lock(element->threadstate);
+}
+
+static void
+gst_schedule_unlock_element (GstSchedule *sched,GstElement *element)
+{
+  cothread_unlock(element->threadstate);
+}
+
+
+/*************** INCREMENTAL SCHEDULING CODE STARTS HERE ***************/
+
+
+static void    gst_schedule_class_init (GstScheduleClass *klass);
+static void    gst_schedule_init       (GstSchedule *schedule);
+
+static GstObjectClass *parent_class = NULL;
+
+GtkType gst_schedule_get_type(void) {
+  static GtkType schedule_type = 0;
+
+  if (!schedule_type) {
+    static const GtkTypeInfo schedule_info = {
+      "GstSchedule",
+      sizeof(GstSchedule),
+      sizeof(GstScheduleClass),
+      (GtkClassInitFunc)gst_schedule_class_init,
+      (GtkObjectInitFunc)gst_schedule_init,
+      (GtkArgSetFunc)NULL,
+      (GtkArgGetFunc)NULL,
+      (GtkClassInitFunc)NULL,
+    };
+    schedule_type = gtk_type_unique(GST_TYPE_OBJECT,&schedule_info);
+  }
+  return schedule_type;
+}
+
+static void
+gst_schedule_class_init (GstScheduleClass *klass)
+{
+  parent_class = gtk_type_class(GST_TYPE_OBJECT);
+}
+
+static void
+gst_schedule_init (GstSchedule *schedule)
+{
+  schedule->add_element = GST_DEBUG_FUNCPTR(gst_schedule_add_element);
+  schedule->remove_element = GST_DEBUG_FUNCPTR(gst_schedule_remove_element);
+  schedule->enable_element = GST_DEBUG_FUNCPTR(gst_schedule_enable_element);
+  schedule->disable_element = GST_DEBUG_FUNCPTR(gst_schedule_disable_element);
+  schedule->lock_element = GST_DEBUG_FUNCPTR(gst_schedule_lock_element);
+  schedule->unlock_element = GST_DEBUG_FUNCPTR(gst_schedule_unlock_element);
+  schedule->pad_connect = GST_DEBUG_FUNCPTR(gst_schedule_pad_connect);
+  schedule->pad_disconnect = GST_DEBUG_FUNCPTR(gst_schedule_pad_disconnect);
+  schedule->iterate = GST_DEBUG_FUNCPTR(gst_schedule_iterate);
+}
+
+GstSchedule*
+gst_schedule_new(GstElement *parent)
+{
+  GstSchedule *sched = GST_SCHEDULE (gtk_type_new (GST_TYPE_SCHEDULE));
+
+  sched->parent = parent;
+
+  return sched;
+}
+
+
+/* this function will look at a pad and determine if the peer parent is
+ * a possible candidate for connecting up in the same chain. */
+/* DEPRACATED !!!!
+GstElement *gst_schedule_check_pad (GstSchedule *sched, GstPad *pad) {
+  GstRealPad *peer;
+  GstElement *element, *peerelement;
+
+  GST_INFO (GST_CAT_SCHEDULING, "checking pad %s:%s for peer in scheduler",
+            GST_DEBUG_PAD_NAME(pad));
+
+  element = GST_ELEMENT(GST_PAD_PARENT(peer));
+  GST_DEBUG(GST_CAT_SCHEDULING, "element is \"%s\"\n",GST_ELEMENT_NAME(element));
+
+  peer = GST_PAD_PEER (pad);
+  if (peer == NULL) return NULL;
+  peerelement = GST_ELEMENT(GST_PAD_PARENT (peer));
+  if (peerelement == NULL) return NULL;
+  GST_DEBUG(GST_CAT_SCHEDULING, "peer element is \"%s\"\n",GST_ELEMENT_NAME(peerelement));
+
+  // now check to see if it's in the same schedule
+  if (GST_ELEMENT_SCHED(element) == GST_ELEMENT_SCHED(peerelement)) {
+    GST_DEBUG(GST_CAT_SCHEDULING, "peer is in same schedule\n");
+    return peerelement;
+  }
+
+  // otherwise it's not a candidate
+  return NULL;
+}
+*/
+
+GstScheduleChain *
+gst_schedule_chain_new (GstSchedule *sched)
+{
+  GstScheduleChain *chain = g_new (GstScheduleChain, 1);
+
+  // initialize the chain with sane values
+  chain->sched = sched;
+  chain->disabled = NULL;
+  chain->elements = NULL;
+  chain->num_elements = 0;
+  chain->entry = NULL;
+  chain->cothreaded_elements = 0;
+  chain->schedule = FALSE;
+
+  // add the chain to the schedules' list of chains
+  sched->chains = g_list_prepend (sched->chains, chain);
+  sched->num_chains++;
+
+  GST_INFO (GST_CAT_SCHEDULING, "created new chain %p, now are %d chains in sched %p",
+            chain,sched->num_chains,sched);
+
+  return chain;
+}
+
+void
+gst_schedule_chain_destroy (GstScheduleChain *chain)
+{
+  GstSchedule *sched = chain->sched;
+
+  // remove the chain from the schedules' list of chains
+  chain->sched->chains = g_list_remove (chain->sched->chains, chain);
+  chain->sched->num_chains--;
+
+  // destroy the chain
+  g_list_free (chain->disabled);       // should be empty...
+  g_list_free (chain->elements);       // ditto
+  g_free (chain);
+
+  GST_INFO (GST_CAT_SCHEDULING, "destroyed chain %p, now are %d chains in sched %p",chain,sched->num_chains,sched);
+}
+
+void
+gst_schedule_chain_add_element (GstScheduleChain *chain, GstElement *element)
+{
+  GST_INFO (GST_CAT_SCHEDULING, "adding element \"%s\" to chain %p", GST_ELEMENT_NAME (element),chain);
+
+  // set the sched pointer for the element
+  element->sched = chain->sched;
+
+  // add the element to the list of 'disabled' elements
+  chain->disabled = g_list_prepend (chain->disabled, element);
+  chain->num_elements++;
+}
+
+void
+gst_schedule_chain_enable_element (GstScheduleChain *chain, GstElement *element)
+{
+  GST_INFO (GST_CAT_SCHEDULING, "enabling element \"%s\" in chain %p", GST_ELEMENT_NAME (element),chain);
+
+  // remove from disabled list
+  chain->disabled = g_list_remove (chain->disabled, element);
+
+  // add to elements list
+  chain->elements = g_list_prepend (chain->elements, element);
+
+  // reschedule the chain
+  gst_schedule_cothreaded_chain(GST_BIN(chain->sched->parent),chain);
+}
+
+void
+gst_schedule_chain_disable_element (GstScheduleChain *chain, GstElement *element)
+{
+  GST_INFO (GST_CAT_SCHEDULING, "disabling element \"%s\" in chain %p", GST_ELEMENT_NAME (element),chain);
+
+  // remove from elements list
+  chain->elements = g_list_remove (chain->elements, element);
+
+  // add to disabled list
+  chain->disabled = g_list_prepend (chain->disabled, element);
+
+  // reschedule the chain
+// FIXME this should be done only if manager state != NULL
+//  gst_schedule_cothreaded_chain(GST_BIN(chain->sched->parent),chain);
+}
+
+void
+gst_schedule_chain_remove_element (GstScheduleChain *chain, GstElement *element)
+{
+  GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from chain %p", GST_ELEMENT_NAME (element),chain);
+
+  // if it's active, deactivate it
+  if (g_list_find (chain->elements, element)) {
+    gst_schedule_chain_disable_element (chain, element);
+  }
+
+  // remove the element from the list of elements
+  chain->disabled = g_list_remove (chain->disabled, element);
+  chain->num_elements--;
+
+  // if there are no more elements in the chain, destroy the chain
+  if (chain->num_elements == 0)
+    gst_schedule_chain_destroy(chain);
+
+  // unset the sched pointer for the element
+  element->sched = NULL;
+}
+
+void
+gst_schedule_chain_elements (GstSchedule *sched, GstElement *element1, GstElement *element2)
+{
+  GList *chains;
+  GstScheduleChain *chain;
+  GstScheduleChain *chain1 = NULL, *chain2 = NULL;
+  GstElement *element;
+
+  // first find the chains that hold the two 
+  chains = sched->chains;
+  while (chains) {
+    chain = (GstScheduleChain *)(chains->data);
+    chains = g_list_next(chains);
+
+    if (g_list_find (chain->disabled,element1))
+      chain1 = chain;
+    else if (g_list_find (chain->elements,element1))
+      chain1 = chain;
+
+    if (g_list_find (chain->disabled,element2))
+      chain2 = chain;
+    else if (g_list_find (chain->elements,element2))
+      chain2 = chain;
+  }
+
+  // first check to see if they're in the same chain, we're done if that's the case
+  if ((chain1 != NULL) && (chain1 == chain2)) {
+    GST_INFO (GST_CAT_SCHEDULING, "elements are already in the same chain");
+    return;
+  }
+
+  // now, if neither element has a chain, create one
+  if ((chain1 == NULL) && (chain2 == NULL)) {
+    GST_INFO (GST_CAT_SCHEDULING, "creating new chain to hold two new elements");
+    chain = gst_schedule_chain_new (sched);
+    gst_schedule_chain_add_element (chain, element1);
+    gst_schedule_chain_add_element (chain, element2);
+    // FIXME chain changed here
+//    gst_schedule_cothreaded_chain(chain->sched->parent,chain);
+
+  // otherwise if both have chains already, join them
+  } else if ((chain1 != NULL) && (chain2 != NULL)) {
+    GST_INFO (GST_CAT_SCHEDULING, "merging chain %p into chain %p",chain2,chain1);
+    // take the contents of chain2 and merge them into chain1
+    chain1->disabled = g_list_concat (chain1->disabled, g_list_copy(chain2->disabled));
+    chain1->elements = g_list_concat (chain1->elements, g_list_copy(chain2->elements));
+    chain1->num_elements += chain2->num_elements;
+    // FIXME chain changed here
+//    gst_schedule_cothreaded_chain(chain->sched->parent,chain);
+
+    gst_schedule_chain_destroy(chain2);
+
+  // otherwise one has a chain already, the other doesn't
+  } else {
+    // pick out which one has the chain, and which doesn't
+    if (chain1 != NULL) chain = chain1, element = element2;
+    else chain = chain2, element = element1;
+
+    GST_INFO (GST_CAT_SCHEDULING, "adding element to existing chain");
+    gst_schedule_chain_add_element (chain, element);
+    // FIXME chain changed here
+//    gst_schedule_cothreaded_chain(chain->sched->parent,chain);
+  }
+}
+
+void
+gst_schedule_pad_connect (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad)
+{
+  GstElement *srcelement,*sinkelement;
+
+  srcelement = GST_PAD_PARENT(srcpad);
+  g_return_if_fail(srcelement != NULL);
+  sinkelement = GST_PAD_PARENT(sinkpad);
+  g_return_if_fail(sinkelement != NULL);
+
+  GST_INFO (GST_CAT_SCHEDULING, "have pad connected callback on %s:%s to %s:%s",GST_DEBUG_PAD_NAME(srcpad),GST_DEBUG_PAD_NAME(sinkpad));
+  GST_DEBUG(GST_CAT_SCHEDULING, "srcpad sched is %p, sinkpad sched is %p\n",
+GST_ELEMENT_SCHED(srcelement),GST_ELEMENT_SCHED(sinkelement));
+
+  if (GST_ELEMENT_SCHED(srcelement) == GST_ELEMENT_SCHED(sinkelement)) {
+    GST_INFO (GST_CAT_SCHEDULING, "peer %s:%s is in same schedule, chaining together",GST_DEBUG_PAD_NAME(sinkpad));
+    gst_schedule_chain_elements (sched, srcelement, sinkelement);
+  }
+}
+
+// find the chain within the schedule that holds the element, if any
+GstScheduleChain *
+gst_schedule_find_chain (GstSchedule *sched, GstElement *element)
+{
+  GList *chains;
+  GstScheduleChain *chain;
+
+  GST_INFO (GST_CAT_SCHEDULING, "searching for element \"%s\" in chains",GST_ELEMENT_NAME(element));
+
+  chains = sched->chains;
+  while (chains) {
+    chain = (GstScheduleChain *)(chains->data);
+    chains = g_list_next (chains);
+
+    if (g_list_find (chain->elements, element))
+      return chain;
+    if (g_list_find (chain->disabled, element))
+      return chain;
+  }
 
+  return NULL;
+}
+
+void
+gst_schedule_chain_recursive_add (GstScheduleChain *chain, GstElement *element)
+{
+  GList *pads;
+  GstPad *pad;
+  GstElement *peerelement;
+
+  // add the element to the chain
+  gst_schedule_chain_add_element (chain, element);
+
+  GST_DEBUG(GST_CAT_SCHEDULING, "recursing on element \"%s\"\n",GST_ELEMENT_NAME(element));
+  // now go through all the pads and see which peers can be added
+  pads = element->pads;
+  while (pads) {
+    pad = GST_PAD(pads->data);
+    pads = g_list_next (pads);
+
+    GST_DEBUG(GST_CAT_SCHEDULING, "have pad %s:%s, checking for valid peer\n",GST_DEBUG_PAD_NAME(pad));
+    // if the peer exists and could be in the same chain
+    if (GST_PAD_PEER(pad)) {
+      GST_DEBUG(GST_CAT_SCHEDULING, "has peer %s:%s\n",GST_DEBUG_PAD_NAME(GST_PAD_PEER(pad)));
+      peerelement = GST_PAD_PARENT(GST_PAD_PEER(pad));
+      if (GST_ELEMENT_SCHED(GST_PAD_PARENT(pad)) == GST_ELEMENT_SCHED(peerelement)) {
+        GST_DEBUG(GST_CAT_SCHEDULING, "peer \"%s\" is valid for same chain\n",GST_ELEMENT_NAME(peerelement));
+        // if it's not already in a chain, add it to this one
+        if (gst_schedule_find_chain (chain->sched, peerelement) == NULL) {
+          gst_schedule_chain_recursive_add (chain, peerelement);
+        }
+      }
+    }
+  }
+}
+
+void
+gst_schedule_pad_disconnect (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad)
+{
+  GstScheduleChain *chain;
+  GstElement *element1, *element2;
+  GstScheduleChain *chain1, *chain2;
+
+  GST_INFO (GST_CAT_SCHEDULING, "disconnecting pads %s:%s and %s:%s",
+            GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
+
+  // we need to have the parent elements of each pad
+  element1 = GST_ELEMENT(GST_PAD_PARENT(srcpad));
+  element2 = GST_ELEMENT(GST_PAD_PARENT(sinkpad));
+
+  // first task is to remove the old chain they belonged to.
+  // this can be accomplished by taking either of the elements,
+  // since they are guaranteed to be in the same chain
+  // FIXME is it potentially better to make an attempt at splitting cleaner??
+  chain = gst_schedule_find_chain (sched, element1);
+  if (chain) {
+    GST_INFO (GST_CAT_SCHEDULING, "destroying chain");
+    gst_schedule_chain_destroy (chain);
+  }
+
+  // now create a new chain to hold element1 and build it from scratch
+  chain1 = gst_schedule_chain_new (sched);
+  gst_schedule_chain_recursive_add (chain1, element1);
+
+  // check the other element to see if it landed in the newly created chain
+  if (gst_schedule_find_chain (sched, element2) == NULL) {
+    // if not in chain, create chain and build from scratch
+    chain2 = gst_schedule_chain_new (sched);
+    gst_schedule_chain_recursive_add (chain2, element2);
+  }
+}
+
+
+void
+gst_schedule_add_element (GstSchedule *sched, GstElement *element)
+{
+  GList *pads;
+  GstPad *pad;
+  GstElement *peerelement;
+  GstScheduleChain *chain;
+
+  g_return_if_fail (element != NULL);
+  g_return_if_fail (GST_IS_ELEMENT(element));
+
+  // if it's already in this schedule, don't bother doing anything
+  if (GST_ELEMENT_SCHED(element) == sched) return;
+
+  GST_INFO (GST_CAT_SCHEDULING, "adding element \"%s\" to schedule",
+    GST_ELEMENT_NAME(element));
+
+  // if the element already has a different scheduler, remove the element from it
+  if (GST_ELEMENT_SCHED(element)) {
+    gst_schedule_remove_element(GST_ELEMENT_SCHED(element),element);
+  }
+
+  // set the sched pointer in the element itself
+  GST_ELEMENT_SCHED(element) = sched;
+
+  // only deal with elements after this point, not bins
+  // exception is made for Bin's that are schedulable, like the autoplugger
+  if (GST_IS_BIN (element) && !GST_FLAG_IS_SET(element, GST_BIN_SELF_SCHEDULABLE)) return;
+
+  // first add it to the list of elements that are to be scheduled
+  sched->elements = g_list_prepend (sched->elements, element);
+  sched->num_elements++;
+
+  // create a chain to hold it, and add
+  chain = gst_schedule_chain_new (sched);
+  gst_schedule_chain_add_element (chain, element);
+
+  // set the sched pointer in all the pads
+  pads = element->pads;
+  while (pads) {
+    pad = GST_PAD(pads->data);
+    pads = g_list_next(pads);
+
+    // we only operate on real pads
+    if (!GST_IS_REAL_PAD(pad)) continue;
+
+    // set the pad's sched pointer
+    gst_pad_set_sched (pad, sched);
+
+    // if the peer element exists and is a candidate
+    if (GST_PAD_PEER(pad)) {
+      peerelement = GST_PAD_PARENT( GST_PAD_PEER (pad) );
+      if (GST_ELEMENT_SCHED(element) == GST_ELEMENT_SCHED(peerelement)) {
+        GST_INFO (GST_CAT_SCHEDULING, "peer is in same schedule, chaining together");
+        // make sure that the two elements are in the same chain
+        gst_schedule_chain_elements (sched,element,peerelement);
+      }
+    }
+  }
+}
+
+void
+gst_schedule_enable_element (GstSchedule *sched, GstElement *element)
+{
+  GstScheduleChain *chain;
+
+  // find the chain the element's in
+  chain = gst_schedule_find_chain (sched, element);
+
+  if (chain)
+    gst_schedule_chain_enable_element (chain, element);
+  else
+    GST_INFO (GST_CAT_SCHEDULING, "element not found in any chain, not enabling");
+}
+
+void
+gst_schedule_disable_element (GstSchedule *sched, GstElement *element)
+{
+  GstScheduleChain *chain;
+
+  // find the chain the element is in
+  chain = gst_schedule_find_chain (sched, element);
+
+  // remove it from the chain
+  if (chain) {
+    gst_schedule_chain_disable_element(chain,element);
+  }
+}
+
+void
+gst_schedule_remove_element (GstSchedule *sched, GstElement *element)
+{
+  GstScheduleChain *chain;
+
+  g_return_if_fail (element != NULL);
+  g_return_if_fail (GST_IS_ELEMENT(element));
+
+  if (g_list_find (sched->elements, element)) {
+    GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from schedule",
+      GST_ELEMENT_NAME(element));
+
+    // find what chain the element is in
+    chain = gst_schedule_find_chain(sched, element);
+
+    // remove it from its chain
+    gst_schedule_chain_remove_element (chain, element);
+
+    // remove it from the list of elements
+    sched->elements = g_list_remove (sched->elements, element);
+    sched->num_elements--;
+
+    // unset the scheduler pointer in the element
+    GST_ELEMENT_SCHED(element) = NULL;
+  }
+}
+
+gboolean
+gst_schedule_iterate (GstSchedule *sched)
+{
+  GstBin *bin = GST_BIN(sched->parent);
+  GList *chains;
+  GstScheduleChain *chain;
+  GstElement *entry;
+  gint num_scheduled = 0;
+  gboolean eos = FALSE;
+  GList *elements;
+
+  GST_DEBUG_ENTER("(\"%s\")", GST_ELEMENT_NAME (bin));
+
+  g_return_val_if_fail (bin != NULL, TRUE);
+  g_return_val_if_fail (GST_IS_BIN (bin), TRUE);
+//  g_return_val_if_fail (GST_STATE (bin) == GST_STATE_PLAYING, TRUE);
+
+  // step through all the chains
+  chains = sched->chains;
+//  if (chains == NULL) return FALSE;
+g_return_val_if_fail (chains != NULL, FALSE);
+  while (chains) {
+    chain = (GstScheduleChain *)(chains->data);
+    chains = g_list_next (chains);
+
+//    if (!chain->need_scheduling) continue;
+
+//    if (chain->need_cothreads) {
+      // all we really have to do is switch to the first child
+      // FIXME this should be lots more intelligent about where to start
+      GST_DEBUG (GST_CAT_DATAFLOW,"starting iteration via cothreads\n");
+
+      if (chain->elements) {
+        entry = NULL; //MattH ADDED?
+GST_DEBUG(GST_CAT_SCHEDULING,"there are %d elements in this chain\n",chain->num_elements);
+        elements = chain->elements;
+        while (elements) {
+          entry = GST_ELEMENT(elements->data);
+          elements = g_list_next(elements);
+          if (GST_FLAG_IS_SET(entry,GST_ELEMENT_DECOUPLED)) {
+            GST_DEBUG(GST_CAT_SCHEDULING,"entry \"%s\" is DECOUPLED, skipping\n",GST_ELEMENT_NAME(entry));
+            entry = NULL;
+          } else if (GST_FLAG_IS_SET(entry,GST_ELEMENT_NO_ENTRY)) {
+            GST_DEBUG(GST_CAT_SCHEDULING,"entry \"%s\" is not valid, skipping\n",GST_ELEMENT_NAME(entry));
+            entry = NULL;
+          } else
+            break;
+        }
+        if (entry) {
+          GST_FLAG_SET (entry, GST_ELEMENT_COTHREAD_STOPPING);
+          GST_DEBUG (GST_CAT_DATAFLOW,"set COTHREAD_STOPPING flag on \"%s\"(@%p)\n",
+               GST_ELEMENT_NAME (entry),entry);
+          cothread_switch (entry->threadstate);
+
+          // following is a check to see if the chain was interrupted due to a
+          // top-half state_change().  (i.e., if there's a pending state.)
+          //
+          // if it was, return to gstthread.c::gst_thread_main_loop() to
+          // execute the state change.
+          GST_DEBUG (GST_CAT_DATAFLOW,"cothread switch ended or interrupted\n");
+          if (GST_STATE_PENDING(GST_SCHEDULE(sched)->parent) != GST_STATE_NONE_PENDING)
+          {
+            GST_DEBUG (GST_CAT_DATAFLOW,"handle pending state %d\n",
+                       GST_STATE_PENDING(GST_SCHEDULE(sched)->parent));
+            return 0;
+          }
+
+        } else {
+          GST_INFO (GST_CAT_DATAFLOW,"NO ENTRY INTO CHAIN!");
+        }
+      } else {
+        GST_INFO (GST_CAT_DATAFLOW,"NO ENABLED ELEMENTS IN CHAIN!!");
+      }
+
+/*                
+    } else {
+      GST_DEBUG (GST_CAT_DATAFLOW,"starting iteration via chain-functions\n");
+
+      entries = chain->entries;
+         
+      g_assert (entries != NULL);
+     
+      while (entries) {
+        entry = GST_ELEMENT (entries->data);
+        entries = g_list_next (entries);
+        GST_DEBUG (GST_CAT_DATAFLOW,"have entry \"%s\"\n",GST_ELEMENT_NAME (entry));
+  
+        if (GST_IS_BIN (entry)) {
+          gst_bin_iterate (GST_BIN (entry));
+        } else {
+          pads = entry->pads;
+          while (pads) {
+            pad = GST_PAD (pads->data);
+            if (GST_RPAD_DIRECTION(pad) == GST_PAD_SRC) {
+              GST_DEBUG (GST_CAT_DATAFLOW,"calling getfunc of %s:%s\n",GST_DEBUG_PAD_NAME(pad));
+              if (GST_REAL_PAD(pad)->getfunc == NULL) 
+                fprintf(stderr, "error, no getfunc in \"%s\"\n", GST_ELEMENT_NAME  (entry));
+              else
+                buf = (GST_REAL_PAD(pad)->getfunc)(pad);
+              if (buf) gst_pad_push(pad,buf);
+            }
+            pads = g_list_next (pads);
+          }
+        }
+      }
+    }*/
+    num_scheduled++;
+  }
+
+/*
+  // check if nothing was scheduled that was ours..
+  if (!num_scheduled) {
+    // are there any other elements that are still busy?
+    if (bin->num_eos_providers) {
+      GST_LOCK (bin);
+      GST_DEBUG (GST_CATA_DATAFLOW,"waiting for eos providers\n");
+      g_cond_wait (bin->eoscond, GST_OBJECT(bin)->lock);  
+      GST_DEBUG (GST_CAT_DATAFLOW,"num eos providers %d\n", bin->num_eos_providers);
+      GST_UNLOCK (bin);
+    }
+    else {      
+      gst_element_signal_eos (GST_ELEMENT (bin));
+      eos = TRUE;
+    }       
+  }
+*/
+
+  GST_DEBUG (GST_CAT_DATAFLOW, "leaving (%s)\n", GST_ELEMENT_NAME (bin));
+  return !eos;
+}
+
+
+
+void
+gst_schedule_show (GstSchedule *sched)
+{
+  GList *chains, *elements;
+  GstElement *element;
+  GstScheduleChain *chain;
+
+  if (sched == NULL) {
+    g_print("schedule doesn't exist for this element\n");
+    return;
+  }
+
+  g_return_if_fail(GST_IS_SCHEDULE(sched));
+
+  g_print("SCHEDULE DUMP FOR MANAGING BIN \"%s\"\n",GST_ELEMENT_NAME(sched->parent));
+
+  g_print("schedule has %d elements in it: ",sched->num_elements);
+  elements = sched->elements;
+  while (elements) {
+    element = GST_ELEMENT(elements->data);
+    elements = g_list_next(elements);
+
+    g_print("%s, ",GST_ELEMENT_NAME(element));
+  }
+  g_print("\n");
+
+  g_print("schedule has %d chains in it\n",sched->num_chains);
+  chains = sched->chains;
+  while (chains) {
+    chain = (GstScheduleChain *)(chains->data);
+    chains = g_list_next(chains);
+
+    g_print("%p: ",chain);
+
+    elements = chain->disabled;
+    while (elements) {
+      element = GST_ELEMENT(elements->data);
+      elements = g_list_next(elements);
+
+      g_print("!%s, ",GST_ELEMENT_NAME(element));
+    }
+
+    elements = chain->elements;
+    while (elements) {
+      element = GST_ELEMENT(elements->data);
+      elements = g_list_next(elements);
+
+      g_print("%s, ",GST_ELEMENT_NAME(element));
+    }
+    g_print("\n");
+  }
+}
index 5cfbfff..cdc9052 100644 (file)
@@ -24,6 +24,7 @@
 #ifndef __GST_SCHEDULER_H__
 #define __GST_SCHEDULER_H__
 
+#include <gst/gstelement.h>
 #include <gst/gstbin.h>
 
 
@@ -32,8 +33,106 @@ extern "C" {
 #endif /* __cplusplus */
 
 
+#define GST_TYPE_SCHEDULE \
+  (gst_schedule_get_type())
+#define GST_SCHEDULE(obj) \
+  (GTK_CHECK_CAST((obj),GST_TYPE_SCHEDULE,GstSchedule))
+#define GST_SCHEDULE_CLASS(klass) \
+  (GTK_CHECK_CLASS_CAST((klass),GST_TYPE_SCHEDULE,GstScheduleClass))
+#define GST_IS_SCHEDULE(obj) \
+  (GTK_CHECK_TYPE((obj),GST_TYPE_SCHEDULE))
+#define GST_IS_SCHEDULE_CLASS(klass) \
+  (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_SCHEDULE))
+
+
+#define GST_SCHED_PARENT(sched)                ((sched)->parent)
+
+//typedef struct _GstSchedule GstSchedule;
+//typedef struct _GstScheduleClass GstScheduleClass;
+typedef struct _GstScheduleChain GstScheduleChain;
+
+struct _GstSchedule {
+  GstObject object;
+
+  GstElement *parent;
+
+  GList *elements;
+  gint num_elements;
+
+  GList *chains;
+  gint num_chains;
+
+  void (*add_element)          (GstSchedule *sched, GstElement *element);
+  void (*remove_element)       (GstSchedule *sched, GstElement *element);
+  void (*enable_element)       (GstSchedule *sched, GstElement *element);
+  void (*disable_element)      (GstSchedule *sched, GstElement *element);
+  void (*lock_element)         (GstSchedule *sched, GstElement *element);
+  void (*unlock_element)       (GstSchedule *sched, GstElement *element);
+  void (*pad_connect)          (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
+  void (*pad_disconnect)       (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
+  gboolean (*iterate)          (GstSchedule *sched);
+};
+
+struct _GstScheduleClass {
+  GstObjectClass parent_class;
+};
+
+//#define GST_SCHEDULE_SAFETY if (sched)
+#define GST_SCHEDULE_SAFETY
+
+#define GST_SCHEDULE_ADD_ELEMENT(sched,element) \
+  GST_SCHEDULE_SAFETY ((sched)->add_element((sched),(element)))
+#define GST_SCHEDULE_REMOVE_ELEMENT(sched,element) \
+  GST_SCHEDULE_SAFETY ((sched)->remove_element((sched),(element)))
+#define GST_SCHEDULE_ENABLE_ELEMENT(sched,element) \
+  GST_SCHEDULE_SAFETY ((sched)->enable_element((sched),(element)))
+#define GST_SCHEDULE_DISABLE_ELEMENT(sched,element) \
+  GST_SCHEDULE_SAFETY ((sched)->disable_element((sched),(element)))
+#define GST_SCHEDULE_LOCK_ELEMENT(sched,element) \
+  GST_SCHEDULE_SAFETY if ((sched)->lock_element != NULL) \
+    ((sched)->lock_element((sched),(element)))
+#define GST_SCHEDULE_UNLOCK_ELEMENT(sched,element) \
+  GST_SCHEDULE_SAFETY if ((sched)->unlock_element != NULL) \
+    ((sched)->unlock_element((sched),(element)))
+#define GST_SCHEDULE_PAD_CONNECT(sched,srcpad,sinkpad) \
+  GST_SCHEDULE_SAFETY ((sched)->pad_connect((sched),(srcpad),(sinkpad)))
+#define GST_SCHEDULE_PAD_DISCONNECT(sched,srcpad,sinkpad) \
+  GST_SCHEDULE_SAFETY ((sched)->pad_disconnect((sched),(srcpad),(sinkpad)))
+#define GST_SCHEDULE_ITERATE(sched) \
+  ((sched)->iterate((sched)))
+
+
+
+struct _GstScheduleChain {
+  GstSchedule *sched;
+
+  GList *disabled;
+
+  GList *elements;
+  gint num_elements;
+
+  GstElement *entry;
+
+  gint cothreaded_elements;
+  gboolean schedule;
+};
+
+
 void gst_bin_schedule_func(GstBin *bin);
 
+GtkType                gst_schedule_get_type           (void);
+GstSchedule *  gst_schedule_new                (GstElement *parent);
+
+void   gst_schedule_add_element        (GstSchedule *sched, GstElement *element);
+void   gst_schedule_remove_element     (GstSchedule *sched, GstElement *element);
+void   gst_schedule_enable_element     (GstSchedule *sched, GstElement *element);
+void   gst_schedule_disable_element    (GstSchedule *sched, GstElement *element);
+void   gst_schedule_pad_connect        (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
+void   gst_schedule_pad_disconnect     (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
+gboolean       gst_schedule_iterate    (GstSchedule *sched);
+
+void   gst_schedule_show               (GstSchedule *sched);
+
 
 #ifdef __cplusplus   
 }
index 1bdea99..8f91ff3 100644 (file)
@@ -26,7 +26,8 @@
 #include "gst_private.h"
 
 #include "gstthread.h"
-
+#include "gstscheduler.h"
+#include "gstqueue.h"
 
 GstElementDetails gst_thread_details = {
   "Threaded container",
@@ -45,14 +46,23 @@ enum {
 };
 
 enum {
+  SPINUP=0,
+  STATECHANGE,
+  STARTUP
+};
+
+enum {
   ARG_0,
   ARG_CREATE_THREAD,
 };
 
 
+
 static void                    gst_thread_class_init           (GstThreadClass *klass);
 static void                    gst_thread_init                 (GstThread *thread);
 
+static void                    gst_thread_real_destroy         (GtkObject *gtk_object);
+
 static void                    gst_thread_set_arg              (GtkObject *object, GtkArg *arg, guint id);
 static void                    gst_thread_get_arg              (GtkObject *object, GtkArg *arg, guint id);
 
@@ -61,9 +71,7 @@ static GstElementStateReturn  gst_thread_change_state         (GstElement *element);
 static xmlNodePtr              gst_thread_save_thyself         (GstObject *object, xmlNodePtr parent);
 static void                    gst_thread_restore_thyself      (GstObject *object, xmlNodePtr self);
 
-static void                    gst_thread_signal_thread        (GstThread *thread);
-static void                    gst_thread_wait_thread          (GstThread *thread);
-static void                    gst_thread_schedule_dummy       (GstBin *bin);
+static void                    gst_thread_signal_thread        (GstThread *thread, gboolean spinning);
 
 static void*                   gst_thread_main_loop            (void *arg);
 
@@ -108,12 +116,14 @@ gst_thread_class_init (GstThreadClass *klass)
   gtk_object_add_arg_type ("GstThread::create_thread", GTK_TYPE_BOOL,
                            GTK_ARG_READWRITE, ARG_CREATE_THREAD);
 
+  gtkobject_class->destroy =           gst_thread_real_destroy;
+
   gstobject_class->save_thyself =      gst_thread_save_thyself;
   gstobject_class->restore_thyself =   gst_thread_restore_thyself;
 
   gstelement_class->change_state =     gst_thread_change_state;
 
-  gstbin_class->schedule = gst_thread_schedule_dummy;
+//  gstbin_class->schedule = gst_thread_schedule_dummy;
 
   gtkobject_class->set_arg = gst_thread_set_arg;
   gtkobject_class->get_arg = gst_thread_get_arg;
@@ -123,26 +133,41 @@ gst_thread_class_init (GstThreadClass *klass)
 static void
 gst_thread_init (GstThread *thread)
 {
-  GST_DEBUG (0,"initializing thread '%s'\n",GST_ELEMENT_NAME (thread));
+
+  GST_DEBUG (GST_CAT_THREAD,"initializing thread\n");
 
   // we're a manager by default
   GST_FLAG_SET (thread, GST_BIN_FLAG_MANAGER);
 
   // default is to create a thread
   GST_FLAG_SET (thread, GST_THREAD_CREATE);
-  GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
 
   thread->lock = g_mutex_new();
   thread->cond = g_cond_new();
+
+  GST_ELEMENT_SCHED(thread) = gst_schedule_new(GST_ELEMENT(thread));
+  GST_DEBUG(GST_CAT_THREAD, "thread's scheduler is %p\n",GST_ELEMENT_SCHED(thread));
+
+  thread->ppid = getpid();
+
+//  gst_element_set_manager(GST_ELEMENT(thread),GST_ELEMENT(thread));
 }
 
 static void
-gst_thread_schedule_dummy (GstBin *bin)
+gst_thread_real_destroy (GtkObject *gtk_object)
 {
-  g_return_if_fail (GST_IS_THREAD (bin));
+  GstThread *thread = GST_THREAD (gtk_object);
+
+  GST_DEBUG (GST_CAT_REFCOUNTING,"destroy()\n");
+
+  g_mutex_free (thread->lock);
+  g_cond_free (thread->cond);
 
-  if (!GST_FLAG_IS_SET (GST_THREAD (bin), GST_THREAD_STATE_SPINNING))
-    GST_INFO (GST_CAT_THREAD,"gstthread: scheduling delayed until thread starts");
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    GTK_OBJECT_CLASS (parent_class)->destroy (gtk_object);
+
+  gst_object_destroy (GST_OBJECT (GST_ELEMENT_SCHED (thread)));
+  gst_object_unref (GST_OBJECT (GST_ELEMENT_SCHED (thread)));
 }
 
 static void
@@ -156,13 +181,13 @@ gst_thread_set_arg (GtkObject *object,
   switch(id) {
     case ARG_CREATE_THREAD:
       if (GTK_VALUE_BOOL (*arg)) {
-        GST_INFO (GST_CAT_THREAD,"gstthread: turning ON the creation of the thread");
+        GST_INFO (GST_CAT_THREAD,"turning ON the creation of the thread");
         GST_FLAG_SET (object, GST_THREAD_CREATE);
-        GST_DEBUG (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
+//        GST_DEBUG (GST_CAT_THREAD,"flags are 0x%08x\n", GST_FLAGS (object));
       } else {
         GST_INFO (GST_CAT_THREAD,"gstthread: turning OFF the creation of the thread");
         GST_FLAG_UNSET (object, GST_THREAD_CREATE);
-        GST_DEBUG (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
+//        GST_DEBUG (GST_CAT_THREAD,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
       }
       break;
     default:
@@ -197,95 +222,237 @@ gst_thread_get_arg (GtkObject *object,
  * Returns: The new thread
  */
 GstElement*
-gst_thread_new (guchar *name)
+gst_thread_new (const guchar *name)
 {
   return gst_elementfactory_make ("thread", name);
 }
 
 
+#define THR_INFO(format,args...) \
+  GST_INFO_ELEMENT(GST_CAT_THREAD, thread, "sync(" GST_DEBUG_THREAD_FORMAT "): " format , \
+  GST_DEBUG_THREAD_ARGS(thread->pid) , ## args )
+#define THR_DEBUG(format,args...) \
+  GST_DEBUG_ELEMENT(GST_CAT_THREAD, thread, "sync(" GST_DEBUG_THREAD_FORMAT "): " format , \
+  GST_DEBUG_THREAD_ARGS(thread->pid) , ## args )
+
+#define THR_INFO_MAIN(format,args...) \
+  GST_INFO_ELEMENT(GST_CAT_THREAD, thread, "sync-main(" GST_DEBUG_THREAD_FORMAT "): " format , \
+  GST_DEBUG_THREAD_ARGS(thread->ppid) , ## args )
+#define THR_DEBUG_MAIN(format,args...) \
+  GST_DEBUG_ELEMENT(GST_CAT_THREAD, thread, "sync-main(" GST_DEBUG_THREAD_FORMAT "): " format , \
+  GST_DEBUG_THREAD_ARGS(thread->ppid) , ## args )
+
 
 static GstElementStateReturn
 gst_thread_change_state (GstElement *element)
 {
   GstThread *thread;
   gboolean stateset = GST_STATE_SUCCESS;
-  gint pending, transition;
+  gint transition;
+  pthread_t self = pthread_self();
+  GstElement *peerelement;
 
   g_return_val_if_fail (GST_IS_THREAD(element), FALSE);
-  GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME(element));
+//  GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME(element));
 
   thread = GST_THREAD (element);
+//  GST_DEBUG (GST_CAT_THREAD, "**** THREAD %ld changing THREAD %ld ****\n",self,thread->thread_id);
+//  GST_DEBUG (GST_CAT_THREAD, "**** current pid=%d\n",getpid());
 
-  GST_INFO (GST_CAT_THREAD,"gstthread: thread \"%s\" change state %d",
-               GST_ELEMENT_NAME (GST_ELEMENT (element)),
-              GST_STATE_PENDING (element));
-
-  pending = GST_STATE_PENDING (element);
   transition = GST_STATE_TRANSITION (element);
 
-//  if (pending == GST_STATE (element)) return GST_STATE_SUCCESS;
+  THR_INFO("changing state from %s to %s",
+           gst_element_statename(GST_STATE (element)),
+           gst_element_statename(GST_STATE_PENDING (element)));
 
-  GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
-
-  if (GST_ELEMENT_CLASS (parent_class)->change_state)
-    stateset = GST_ELEMENT_CLASS (parent_class)->change_state (element);
-
-  GST_INFO (GST_CAT_THREAD, "gstthread: stateset %d %d %d %02x", GST_STATE (element), stateset,
-                 GST_STATE_PENDING (element), GST_STATE_TRANSITION (element));
+  //GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
 
   switch (transition) {
     case GST_STATE_NULL_TO_READY:
-//      if (!stateset) return FALSE;
-      // we want to prepare our internal state for doing the iterations
-      GST_INFO (GST_CAT_THREAD, "gstthread: preparing thread \"%s\" for iterations:",
-               GST_ELEMENT_NAME (GST_ELEMENT (element)));
-
       // set the state to idle
       GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
-      // create the thread if that's what we're supposed to do
-      GST_INFO (GST_CAT_THREAD, "gstthread: flags are 0x%08x", GST_FLAGS (thread));
+      GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
 
+      // create the thread if that's what we're supposed to do
       if (GST_FLAG_IS_SET (thread, GST_THREAD_CREATE)) {
-        GST_INFO (GST_CAT_THREAD, "gstthread: starting thread \"%s\"",
-                 GST_ELEMENT_NAME (GST_ELEMENT (element)));
+        THR_DEBUG ("creating thread \"%s\"\n",
+                   GST_ELEMENT_NAME (element));
 
         g_mutex_lock (thread->lock);
+
         // create the thread
         pthread_create (&thread->thread_id, NULL,
                         gst_thread_main_loop, thread);
 
         // wait for it to 'spin up'
-        //gst_thread_wait_thread (thread);
-        g_cond_wait (thread->cond, thread->lock);
-        g_mutex_unlock (thread->lock);
+        THR_DEBUG("waiting for child thread spinup\n");
+        g_cond_wait(thread->cond,thread->lock);
+        THR_DEBUG("thread claims to be up\n");
+        g_mutex_unlock(thread->lock);
       } else {
-        GST_INFO (GST_CAT_THREAD, "gstthread: NOT starting thread \"%s\"",
+        GST_INFO (GST_CAT_THREAD, "NOT creating thread \"%s\"",
                 GST_ELEMENT_NAME (GST_ELEMENT (element)));
+
+        // punt and change state on all the children
+        if (GST_ELEMENT_CLASS (parent_class)->change_state)
+          stateset = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+      }
+      break;
+    case GST_STATE_READY_TO_PAUSED:
+      THR_INFO("readying thread");
+
+      // check to see if the thread is somehow changing its own state.
+      // FIXME this is currently illegal, but must somehow be made legal at some point.
+      if (pthread_equal(self, thread->thread_id))
+      {
+        //FIXME this should not happen
+        g_assert(!pthread_equal(self, thread->thread_id));
+        GST_FLAG_SET(thread, GST_THREAD_STATE_SPINNING);
+        GST_DEBUG(GST_CAT_THREAD,"no sync(" GST_DEBUG_THREAD_FORMAT "): setting own thread's state to spinning\n",
+                  GST_DEBUG_THREAD_ARGS(thread->pid));
+      }
+      else
+      {
+        g_mutex_lock(thread->lock);
+        gst_thread_signal_thread(thread,FALSE);
       }
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
-    case GST_STATE_READY_TO_PLAYING:
-      if (!stateset) return FALSE;
-      GST_INFO (GST_CAT_THREAD, "gstthread: starting thread \"%s\"",
-              GST_ELEMENT_NAME (GST_ELEMENT (element)));
-
-      GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
-      gst_thread_signal_thread (thread);
+      THR_INFO("starting thread");
+
+      // check to see if the thread is somehow changing its own state.
+      // FIXME this is currently illegal, but must somehow be made legal at some point.
+      if (pthread_equal(self, thread->thread_id))
+      {
+        //FIXME this should not happen
+        g_assert(!pthread_equal(self, thread->thread_id));
+        GST_FLAG_SET(thread, GST_THREAD_STATE_SPINNING);
+        GST_DEBUG(GST_CAT_THREAD,"no sync(" GST_DEBUG_THREAD_FORMAT "): setting own thread's state to spinning\n",
+                  GST_DEBUG_THREAD_ARGS(thread->pid));
+      }
+      else
+      {
+        THR_DEBUG("telling thread to start spinning\n");
+        g_mutex_lock(thread->lock);
+        gst_thread_signal_thread(thread,TRUE);
+      }
       break;
     case GST_STATE_PLAYING_TO_PAUSED:
-      GST_INFO (GST_CAT_THREAD,"gstthread: pausing thread \"%s\"",
-              GST_ELEMENT_NAME (GST_ELEMENT (element)));
-
-      //GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
-      gst_thread_signal_thread (thread);
+      THR_INFO("pausing thread");
+
+      // check to see if the thread is somehow changing its own state.
+      // FIXME this is currently illegal, but must somehow be made legal at some point.
+      if (pthread_equal(self, thread->thread_id))
+      {
+        //FIXME this should not happen
+        GST_DEBUG(GST_CAT_THREAD,"no sync(" GST_DEBUG_THREAD_FORMAT "): setting own thread's state to paused\n",
+                  GST_DEBUG_THREAD_ARGS(thread->pid));
+        GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+        g_assert(!pthread_equal(self, thread->thread_id));
+      }
+      else
+      {
+        GList *elements = (element->sched)->elements;
+
+        // the following code ensures that the bottom half of thread will run
+        // to perform each elements' change_state() (by calling gstbin.c::
+        // change_state()).
+        // + the pending state was already set by gstelement.c::set_state()
+        // + find every queue we manage, and signal its empty and full conditions
+
+        g_mutex_lock(thread->lock);
+
+        GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+
+        while (elements)
+        {
+          GstElement *e = GST_ELEMENT(elements->data);
+          g_assert(e);
+          THR_DEBUG("  element \"%s\"\n",GST_ELEMENT_NAME(e));
+          elements = g_list_next(elements);
+          if (GST_IS_QUEUE(e))
+          {
+            //FIXME make this more efficient by only waking queues that are asleep
+            //FIXME and only waking the appropriate condition (depending on if it's
+            //FIXME on up- or down-stream side)
+            //
+            //FIXME also make this more efficient by keeping list of managed queues
+            THR_DEBUG("waking queue \"%s\"\n",GST_ELEMENT_NAME(e));
+            GST_LOCK(e);
+            g_cond_signal((GST_QUEUE(e)->emptycond));
+            g_cond_signal((GST_QUEUE(e)->fullcond));
+            GST_UNLOCK(e);
+          }
+          else
+          {
+            GList *pads = GST_ELEMENT_PADS(e);
+            while (pads)
+            {
+              GstPad *p = GST_PAD(pads->data);
+              pads = g_list_next(pads);
+
+              peerelement = GST_PAD_PARENT(GST_PAD_PEER(p));
+              if (!peerelement) continue;              // deal with case where there's no peer
+
+              if (!GST_FLAG_IS_SET(peerelement,GST_ELEMENT_DECOUPLED)) {
+                GST_DEBUG(GST_CAT_THREAD,"peer element isn't DECOUPLED\n");
+                continue;
+              }
+
+              // FIXME this needs to go away eventually
+              if (!GST_IS_QUEUE(peerelement)) {
+                GST_DEBUG(GST_CAT_THREAD,"peer element isn't a Queue\n");
+                continue;
+              }
+
+              if (GST_ELEMENT_SCHED(peerelement) != GST_ELEMENT_SCHED(thread))
+              {
+                THR_DEBUG("  element \"%s\" has pad cross sched boundary\n",GST_ELEMENT_NAME(e));
+                GST_LOCK(peerelement);
+                g_cond_signal(GST_QUEUE(peerelement)->emptycond);
+                g_cond_signal(GST_QUEUE(peerelement)->fullcond);
+                GST_UNLOCK(peerelement);
+              }
+            }
+          }
+        }
+        THR_DEBUG("waiting for thread to stop spinning\n");
+        g_cond_wait (thread->cond, thread->lock);
+        THR_DEBUG("telling thread to pause\n");
+        gst_thread_signal_thread(thread,FALSE);
+      }
       break;
     case GST_STATE_READY_TO_NULL:
-      GST_INFO (GST_CAT_THREAD,"gstthread: stopping thread \"%s\"",
-              GST_ELEMENT_NAME (GST_ELEMENT (element)));
+      THR_INFO("stopping thread");
 
       GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
-      gst_thread_signal_thread (thread);
-      pthread_join(thread->thread_id,NULL);
+
+      // check to see if the thread is somehow changing its own state.
+      // FIXME this is currently illegal, but must somehow be made legal at some point.
+      if (pthread_equal(self, thread->thread_id))
+      {
+        //FIXME this should not happen
+        g_assert(!pthread_equal(self, thread->thread_id));
+        THR_DEBUG("setting own thread's state to NULL (paused)\n");
+        GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+      }
+      else
+      {
+        THR_DEBUG("telling thread to pause (null) - and joining\n");
+        //MattH FIXME revisit
+//        g_mutex_lock(thread->lock);
+//        gst_thread_signal_thread(thread,FALSE);
+        pthread_join(thread->thread_id,NULL);
+      }
+
+      GST_FLAG_UNSET(thread,GST_THREAD_STATE_REAPING);
+      GST_FLAG_UNSET(thread,GST_THREAD_STATE_STARTED);
+      GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
+      GST_FLAG_UNSET(thread,GST_THREAD_STATE_ELEMENT_CHANGED);
+
+      if (GST_ELEMENT_CLASS (parent_class)->change_state)
+        stateset = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
+
       break;
     default:
       break;
@@ -294,6 +461,16 @@ gst_thread_change_state (GstElement *element)
   return stateset;
 }
 
+static void gst_thread_update_state (GstThread *thread)
+{
+  // check for state change
+  if (GST_STATE_PENDING(thread) != GST_STATE_NONE_PENDING) {
+    // punt and change state on all the children
+    if (GST_ELEMENT_CLASS (parent_class)->change_state)
+      GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
+  }
+}
+
 /**
  * gst_thread_main_loop:
  * @arg: the thread to start
@@ -305,53 +482,186 @@ static void *
 gst_thread_main_loop (void *arg)
 {
   GstThread *thread = GST_THREAD (arg);
+  gint stateset;
+
+  thread->pid = getpid();
+  THR_INFO_MAIN("thread is running");
 
-  GST_INFO (GST_CAT_THREAD,"gstthread: thread \"%s\" is running with PID %d",
-                 GST_ELEMENT_NAME (GST_ELEMENT (thread)), getpid ());
+  // first we need to change the state of all the children
+  if (GST_ELEMENT_CLASS (parent_class)->change_state)
+    stateset = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
 
   // construct the plan and signal back
+/* DEPRACATED for INCSCHED1
+  THR_DEBUG_MAIN("creating plan for thread\n");
   if (GST_BIN_CLASS (parent_class)->schedule)
     GST_BIN_CLASS (parent_class)->schedule (GST_BIN (thread));
+*/
+
+//  THR_DEBUG_MAIN("indicating spinup\n");
+  g_mutex_lock (thread->lock);
+  g_cond_signal (thread->cond);
+  // don't unlock the mutex because we hold it into the top of the while loop
+  THR_DEBUG_MAIN("thread has indicated spinup to parent process\n");
 
-  gst_thread_signal_thread (thread);
+  /***** THREAD IS NOW IN READY STATE *****/
 
   while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) {
-    if (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
+    // NOTE we hold the thread lock at this point
+    // what we do depends on what state we're in
+    switch (GST_STATE(thread)) {
+      // NOTE: cannot be in NULL, we're not running in that state at all
+      case GST_STATE_READY:
+        // wait to be set to either the NULL or PAUSED states
+        THR_DEBUG_MAIN("thread in %s state, waiting for either %s or %s\n",
+                       gst_element_statename(GST_STATE_READY),
+                       gst_element_statename(GST_STATE_NULL),
+                       gst_element_statename(GST_STATE_PAUSED));
+        g_cond_wait(thread->cond,thread->lock);
+        // been signaled, we need to state transition now and signal back
+        gst_thread_update_state(thread);
+        THR_DEBUG_MAIN("done with state transition, signaling back to parent process\n");
+        g_cond_signal(thread->cond);
+//        g_mutex_unlock(thread->lock);
+        // now we decide what to do next (FIXME can be collapsed to a continue)
+        if (GST_STATE(thread) == GST_STATE_NULL) {
+          // REAPING must be set, we can simply break this iteration
+          continue;
+        } else {
+          // PAUSED is the next state, we can wait for that next
+          continue;
+        }
+        break;
+      case GST_STATE_PAUSED:
+        // wait to be set to either the READY or PLAYING states
+        THR_DEBUG_MAIN("thread in %s state, waiting for either %s or %s\n",
+                       gst_element_statename(GST_STATE_PAUSED),
+                       gst_element_statename(GST_STATE_READY),
+                       gst_element_statename(GST_STATE_PLAYING));
+        g_cond_wait(thread->cond,thread->lock);
+        // been signaled, we need to state transition now and signal back
+        gst_thread_update_state(thread);
+        g_cond_signal(thread->cond);
+//        g_mutex_unlock(thread->lock);
+        // now we decide what to do next
+        if (GST_STATE(thread) == GST_STATE_READY) {
+          // READY is the next state, we can wait for that next
+          continue;
+        } else {
+          g_mutex_unlock(thread->lock);
+          // PLAYING is coming up, so we can now start spinning
+          while (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
+            if (!gst_bin_iterate (GST_BIN (thread))) {
+              GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+              THR_DEBUG_MAIN("removed spinning state due to failed iteration!\n");
+            }
+          }
+          g_mutex_lock(thread->lock);
+          // once we're here, SPINNING has stopped, we should signal that we're done
+          THR_DEBUG_MAIN("SPINNING stopped, signaling back to parent process\n");
+          g_cond_signal (thread->cond);
+          // now we can wait for PAUSED
+          continue;
+        }
+        break;
+      case GST_STATE_PLAYING:
+        // wait to be set to PAUSED
+        THR_DEBUG_MAIN("thread in %s state, waiting for %s\n",
+                       gst_element_statename(GST_STATE_PLAYING),
+                       gst_element_statename(GST_STATE_PAUSED));
+        g_cond_wait(thread->cond,thread->lock);
+        // been signaled, we need to state transition now and signal back
+        gst_thread_update_state(thread);
+        g_cond_signal(thread->cond);
+//        g_mutex_unlock(thread->lock);
+        // now we decide what to do next
+        // there's only PAUSED, we we just wait for it
+        continue;
+        break;
+    }
+
+    // need to grab the lock so we're ready for the top of the loop
+//    g_mutex_lock(thread->lock);
+  }
+
+/*
+  while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) {
+    // start out by waiting for a state change into spinning
+    THR_DEBUG_MAIN("waiting for signal from parent process (at top of while())\n");
+    g_cond_wait (thread->cond,thread->lock);
+    THR_DEBUG_MAIN("woken up with %s pending\n",gst_element_statename(GST_STATE(thread)));
+    // now is a good time to change the state of the children and the thread itself
+    gst_thread_update_state (thread);
+    THR_DEBUG_MAIN("done changing state, signaling back\n");
+    g_cond_signal (thread->cond);
+    g_mutex_unlock (thread->lock);
+    THR_DEBUG_MAIN("finished sycnronizing with main process\n");
+
+    while (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
       if (!gst_bin_iterate (GST_BIN (thread))) {
        GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+        THR_DEBUG_MAIN("removed spinning state due to failed iteration!\n");
       }
     }
-    else {
-      GST_DEBUG (0, "thread \"%s\" waiting\n", GST_ELEMENT_NAME (GST_ELEMENT (thread)));
-      gst_thread_wait_thread (thread);
+
+    g_mutex_lock (thread->lock);
+
+    if (GST_STATE_PENDING(thread) == GST_STATE_PAUSED) {
+      // we've stopped spinning, because of PLAYING->PAUSED
+      THR_DEBUG_MAIN("SPINNING flag unset, signaling parent process we're stopped\n");
+      // we need to signal back that we've stopped spinning
+      g_cond_signal (thread->cond);
     }
+
+//    THR_DEBUG_MAIN("signaling that the thread is out of the SPINNING loop\n");
+//    g_cond_signal (thread->cond);
+//    g_cond_wait (thread->cond, thread->lock);
+//    THR_DEBUG_MAIN("parent process has signaled at bottom of while\n");
+//    // now change the children's and thread's state
+//    gst_thread_update_state (thread);
+//    THR_DEBUG_MAIN("done changing state, signaling back to parent process\n");
+//    g_cond_signal (thread->cond);
+//    // don't release the mutex, we hold that into the top of the loop
+//    THR_DEBUG_MAIN("done syncing with parent process at bottom of while\n");
   }
+*/
 
-  GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
-// FIXME this should be removed (why's it here???)
-//  //pthread_join (thread->thread_id, 0);
+  // since we don't unlock at the end of the while loop, do it here
+  g_mutex_unlock (thread->lock);
 
   GST_INFO (GST_CAT_THREAD, "gstthread: thread \"%s\" is stopped",
                  GST_ELEMENT_NAME (thread));
   return NULL;
 }
 
+// the set flag is to say whether it should set TRUE or FALSE
+//
+// WARNING: this has synchronization built in!  if you remove or add any
+// locks, waits, signals, or unlocks you need to be sure they match the 
+// code above (in gst_thread_main_loop()).  basically, don't change anything.
 static void
-gst_thread_signal_thread (GstThread *thread)
+gst_thread_signal_thread (GstThread *thread, gboolean spinning)
 {
-  GST_DEBUG (0,"signaling thread\n");
-  g_mutex_lock (thread->lock);
+  // set the spinning state
+  if (spinning) GST_FLAG_SET(thread,GST_THREAD_STATE_SPINNING);
+  else GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+
+  THR_DEBUG("thread locked\n");
+//  g_mutex_lock(thread->lock);
+
+//  if (!spinning) {
+//    THR_DEBUG("waiting for spindown\n");
+//    g_cond_wait (thread->cond, thread->lock);
+//  }
+  THR_DEBUG("signaling\n");
   g_cond_signal (thread->cond);
-  g_mutex_unlock (thread->lock);
-}
+  THR_DEBUG("waiting for ack\n");
+  g_cond_wait (thread->cond,thread->lock);
+  THR_DEBUG("got ack\n");
 
-static void
-gst_thread_wait_thread (GstThread *thread)
-{
-  GST_DEBUG (0,"waiting for thread\n");
-  g_mutex_lock (thread->lock);
-  g_cond_wait (thread->cond, thread->lock);
-  g_mutex_unlock (thread->lock);
+  THR_DEBUG("unlocking\n");
+  g_mutex_unlock(thread->lock);
+  THR_DEBUG("unlocked\n");
 }
 
 
@@ -359,7 +669,7 @@ static void
 gst_thread_restore_thyself (GstObject *object,
                            xmlNodePtr self)
 {
-  GST_DEBUG (0,"gstthread: restore\n");
+  GST_DEBUG (GST_CAT_THREAD,"gstthread: restore\n");
 
   if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
     GST_OBJECT_CLASS (parent_class)->restore_thyself (object, self);
index 8c53a11..be8b49c 100644 (file)
@@ -24,6 +24,7 @@
 #ifndef __GST_THREAD_H__
 #define __GST_THREAD_H__
 
+#include <unistd.h>
 #include <pthread.h>
 
 #include <gst/gstbin.h>
@@ -38,8 +39,11 @@ extern GstElementDetails gst_thread_details;
 
 typedef enum {
   GST_THREAD_CREATE            = GST_BIN_FLAG_LAST,
+
+  GST_THREAD_STATE_STARTED,
   GST_THREAD_STATE_SPINNING,
   GST_THREAD_STATE_REAPING,
+  GST_THREAD_STATE_ELEMENT_CHANGED,
 
   /* padding */
   GST_THREAD_FLAG_LAST                 = GST_BIN_FLAG_LAST + 4,
@@ -64,8 +68,12 @@ struct _GstThread {
   GstBin bin;
 
   pthread_t thread_id;         /* id of the thread, if any */
+  gint pid;                    /* the pid of the thread */
+  gint ppid;                   /* the pid of the thread's parent process */
   GMutex *lock;                        /* thread lock/condititon pair... */
   GCond *cond;                 /* used to control the thread */
+
+  gint transition;             /* the current state transition */
 };
 
 struct _GstThreadClass {
@@ -74,7 +82,7 @@ struct _GstThreadClass {
 
 GtkType        gst_thread_get_type     (void);
 
-GstElement*    gst_thread_new          (guchar *name);
+GstElement*    gst_thread_new          (const guchar *name);
 
 #ifdef __cplusplus
 }
index 437da19..7440898 100644 (file)
@@ -80,7 +80,7 @@ gst_type_register (GstTypeFactory *factory)
     _gst_types =       g_list_prepend (_gst_types, type);
 
     id = type->id;
-    GST_DEBUG (0,"gsttype: new mime type '%s', id %d\n", type->mime, type->id);
+    GST_DEBUG (GST_CAT_TYPES,"gsttype: new mime type '%s', id %d\n", type->mime, type->id);
 
   } else {
     type = gst_type_find_by_id (id);
@@ -108,12 +108,12 @@ guint16 gst_type_find_by_mime_func (const gchar *mime)
   g_return_val_if_fail (mime != NULL, 0);
 
   walk = _gst_types;
-//  GST_DEBUG (0,"searching for '%s'\n",mime);
+//  GST_DEBUG (GST_CAT_TYPES,"searching for '%s'\n",mime);
   mimelen = strlen (mime);
   while (walk) {
     type = (GstType *)walk->data;
     search = type->mime;
-//    GST_DEBUG (0,"checking against '%s'\n",search);
+//    GST_DEBUG (GST_CAT_TYPES,"checking against '%s'\n",search);
     typelen = strlen (search);
     while ((search - type->mime) < typelen) {
       found = strstr (search, mime);
@@ -232,7 +232,7 @@ gst_type_typefind_dummy (GstBuffer *buffer, gpointer priv)
   guint16 typeid;
   GSList *funcs;
 
-  GST_DEBUG (0,"gsttype: need to load typefind function for %s\n", type->mime);
+  GST_DEBUG (GST_CAT_TYPES,"gsttype: need to load typefind function for %s\n", type->mime);
 
   type->typefindfuncs = NULL;
   gst_plugin_load_typefactory (type->mime);
index 78ac04c..2e045e0 100644 (file)
@@ -180,11 +180,25 @@ gst_typefind_chain (GstPad *pad, GstBuffer *buf)
 
       GST_DEBUG (0,"try type :%d \"%s\"\n", type->id, type->mime);
       if (typefindfunc && (caps = typefindfunc (buf, type))) {
-        GST_DEBUG (0,"found type :%d \"%s\"\n", caps->id, type->mime);
+        GST_DEBUG (0,"found type :%d \"%s\" \"%s\"\n", caps->id, type->mime, 
+                       gst_caps_get_name (caps));
        typefind->caps = caps;
+
+       gst_pad_set_caps (pad, caps);
+
+{ /* FIXME: this should all be in an _emit() wrapper eventually */
+        int oldstate = GST_STATE(typefind);
+       gst_object_ref (GST_OBJECT (typefind));
         gtk_signal_emit (GTK_OBJECT (typefind), gst_typefind_signals[HAVE_TYPE],
                              typefind->caps);
-       gst_pad_set_caps (pad, caps);
+        if (GST_STATE(typefind) != oldstate) {
+         gst_object_unref (GST_OBJECT (typefind));
+          GST_DEBUG(0, "state changed during signal, aborting\n");
+          cothread_switch(cothread_current_main());
+        }
+       gst_object_unref (GST_OBJECT (typefind));
+}
+
         goto end;
       }
       funcs = g_slist_next (funcs);
diff --git a/gst/gsttypes.h b/gst/gsttypes.h
new file mode 100644 (file)
index 0000000..a7c07ed
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __GST_TYPES_H__
+#define __GST_TYPES_H__
+
+typedef struct _GstObject GstObject;
+typedef struct _GstObjectClass GstObjectClass;
+typedef struct _GstPad GstPad;
+typedef struct _GstPadClass GstPadClass;
+typedef struct _GstPadTemplate GstPadTemplate;
+typedef struct _GstPadTemplateClass GstPadTemplateClass;
+typedef struct _GstElement GstElement;
+typedef struct _GstElementClass GstElementClass;
+typedef struct _GstBin GstBin;
+typedef struct _GstBinClass GstBinClass;
+typedef struct _GstSchedule GstSchedule;
+typedef struct _GstScheduleClass GstScheduleClass;
+
+#endif
index 146fda0..28f67c9 100644 (file)
@@ -167,7 +167,7 @@ gst_xml_parse_doc (GstXML *xml, xmlDocPtr doc, const guchar *root)
     if (!strcmp(field->name, "element") && (field->ns == xml->ns)) {
       GstElement *element;
 
-      element = gst_element_load_thyself(field, NULL);
+      element = gst_element_restore_thyself(field, NULL);
 
       xml->topelements = g_list_prepend (xml->topelements, element);
     }
index 7b6dc54..5524909 100644 (file)
@@ -37,6 +37,7 @@ noinst_HEADERS = \
        gstplayprivate.h \
        full-screen.h
 
+
 libgstmediaplay_la_LDFLAGS = -rdynamic
 
 gstmediaplay_CFLAGS = $(LIBGLADE_GNOME_CFLAGS)
index 84e2c0f..e42cc3b 100644 (file)
@@ -39,12 +39,11 @@ target_drag_data_received  (GtkWidget          *widget,
                             guint               time,
                            GstMediaPlay       *play)
 {
-       if (strstr (data->data, "file:")) {
-               g_print ("Got: %s\n", &data->data[5]);
-               gdk_threads_leave ();
-               gst_media_play_start_uri (play, g_strchomp (&data->data[5]));
-               gdk_threads_enter ();
-       }
+       g_print ("Got: %s\n", data->data);
+       gdk_threads_leave ();
+       gst_media_play_start_uri (play, g_strchomp (data->data));
+       gdk_threads_enter ();
+
 }
 
 static GtkTargetEntry target_table[] = {
index 78567a3..bdf88d4 100644 (file)
@@ -508,6 +508,7 @@ Arik Devens &lt;arik@gnome.org&gt;
       <last_modification_time>Sun, 06 Aug 2000 15:55:52 GMT</last_modification_time>
     </signal>
     <stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
+    <relief>GTK_RELIEF_NORMAL</relief>
   </widget>
 
   <widget>
@@ -523,6 +524,7 @@ Arik Devens &lt;arik@gnome.org&gt;
       <last_modification_time>Sun, 06 Aug 2000 15:53:48 GMT</last_modification_time>
     </signal>
     <stock_button>GNOME_STOCK_BUTTON_CANCEL</stock_button>
+    <relief>GTK_RELIEF_NORMAL</relief>
   </widget>
 </widget>
 
index 1b8569f..6cb2477 100644 (file)
@@ -1,20 +1,22 @@
 #include <config.h>
 
+#include <string.h>
+
 #include "gstplay.h"
 #include "gstplayprivate.h"
 #include "full-screen.h"
 
-static void gst_play_class_init       (GstPlayClass *klass);
-static void gst_play_init             (GstPlay *play);
+static void gst_play_class_init                (GstPlayClass *klass);
+static void gst_play_init              (GstPlay *play);
 
-static void gst_play_set_arg         (GtkObject *object, GtkArg *arg, guint id);
-static void gst_play_get_arg         (GtkObject *object, GtkArg *arg, guint id);
+static void gst_play_set_arg           (GtkObject *object, GtkArg *arg, guint id);
+static void gst_play_get_arg           (GtkObject *object, GtkArg *arg, guint id);
 
-static void gst_play_realize         (GtkWidget *play);
+static void gst_play_realize           (GtkWidget *play);
 
-static void gst_play_frame_displayed  (GstElement *element, GstPlay *play);
-static void gst_play_have_size               (GstElement *element, guint width, guint height, GstPlay *play);
-static void gst_play_audio_handoff    (GstElement *element, GstPlay *play);
+static void gst_play_frame_displayed   (GstElement *element, GstPlay *play);
+static void gst_play_have_size                 (GstElement *element, guint width, guint height, GstPlay *play);
+static void gst_play_audio_handoff     (GstElement *element, GstPlay *play);
 
 /* signals and args */
 enum {
@@ -118,10 +120,8 @@ gst_play_init (GstPlay *play)
        play->priv = priv;
 
        /* create a new bin to hold the elements */
-       priv->thread = gst_thread_new ("main_thread");
-       g_assert (priv->thread != NULL);
-       priv->bin = gst_bin_new ("main_bin");
-       g_assert (priv->bin != NULL);
+       priv->pipeline = gst_pipeline_new ("main_pipeline");
+       g_assert (priv->pipeline != NULL);
 
        priv->audio_element = gst_elementfactory_make ("osssink", "play_audio");
        g_return_if_fail (priv->audio_element != NULL);
@@ -165,6 +165,12 @@ gst_play_new ()
        return GST_PLAY (gtk_type_new (GST_TYPE_PLAY));
 }
 
+static gboolean
+gst_play_idle_func (gpointer data)
+{
+       return gst_bin_iterate (GST_BIN (data));
+}
+
 static void
 gst_play_eos (GstElement *element,
              GstPlay *play)
@@ -273,53 +279,68 @@ gst_play_object_added (GstAutoplug* autoplug, GstObject *object, GstPlay *play)
 }
 
 static void
-gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
+gst_play_cache_empty (GstElement *element, GstPlay *play)
 {
-       GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
+       GstPlayPrivate *priv;
+       GstElement *new_element;
+
+       priv = (GstPlayPrivate *)play->priv;
+
+       gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+
+       new_element = gst_bin_get_by_name (GST_BIN (priv->pipeline), "new_element");
+
+       gst_element_disconnect (priv->src, "src", priv->cache, "sink");
+       gst_element_disconnect (priv->cache, "src", new_element, "sink");
+       gst_bin_remove (GST_BIN (priv->pipeline), priv->cache);
+       gst_element_connect (priv->src, "src", new_element, "sink");
 
-       *(gboolean *)data = TRUE;
+       gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
 }
 
-static GstCaps*
-gst_play_typefind (GstBin *bin, GstElement *element)
+static void
+gst_play_have_type (GstElement *sink, GstCaps *caps, GstPlay *play)
 {
-       gboolean found = FALSE;
-       GstElement *typefind;
-       GstCaps *caps = NULL;
+       GstPlayPrivate *priv;
+       GstElement *new_element;
+       GstAutoplug *autoplug;
 
-       GST_DEBUG (0, "GstPipeline: typefind for element \"%s\" %p\n",
-                  GST_ELEMENT_NAME (element), &found);
+       GST_DEBUG (0,"GstPipeline: play have type\n");
 
-       typefind = gst_elementfactory_make ("typefind", "typefind");
-       g_return_val_if_fail (typefind != NULL, FALSE);
+       priv = (GstPlayPrivate *)play->priv;
 
-       gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
-                           GTK_SIGNAL_FUNC (gst_play_have_type), &found);
+       gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
 
-       gst_pad_connect (gst_element_get_pad (element, "src"),
-                        gst_element_get_pad (typefind, "sink"));
+       gst_element_disconnect (priv->cache, "src", priv->typefind, "sink");
+       gst_bin_remove (GST_BIN (priv->pipeline), priv->typefind);
 
-       gst_bin_add (bin, typefind);
+       autoplug = gst_autoplugfactory_make ("staticrender");
+       g_assert (autoplug != NULL);
+
+       gtk_signal_connect (GTK_OBJECT (autoplug), "new_object", gst_play_object_added, play);
+
+       new_element = gst_autoplug_to_renderers (autoplug,
+                                                caps,
+                                                priv->video_element,
+                                                priv->audio_element,
+                                                NULL);
 
-       gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
+       if (!new_element) {
+               // FIXME, signal a suitable error
+               return;
+       }
 
-       // push a buffer... the have_type signal handler will set the found flag
-       gst_bin_iterate (bin);
+       gst_element_set_name (new_element, "new_element");
 
-       gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
+       gst_bin_add (GST_BIN (priv->pipeline), new_element);
 
-       if (found) {
-               caps = gst_util_get_pointer_arg (GTK_OBJECT (typefind), "caps");
+       gtk_object_set (GTK_OBJECT (priv->cache), "reset", TRUE, NULL);
 
-               gst_pad_set_caps (gst_element_get_pad (element, "src"), caps);
-       }
+       gst_element_connect (priv->cache, "src", new_element, "sink");
 
-       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));
+       gtk_signal_connect (GTK_OBJECT (priv->pipeline), "eos", GTK_SIGNAL_FUNC (gst_play_eos), play);
 
-       return caps;
+       gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
 }
 
 static gboolean
@@ -349,9 +370,7 @@ GstPlayReturn
 gst_play_set_uri (GstPlay *play, const guchar *uri)
 {
        GstPlayPrivate *priv;
-       GstCaps *src_caps;
-       GstElement *new_element;
-       GstAutoplug *autoplug;
+       gchar* uriloc;
 
        g_return_val_if_fail (play != NULL, GST_PLAY_ERROR);
        g_return_val_if_fail (GST_IS_PLAY (play), GST_PLAY_ERROR);
@@ -362,47 +381,51 @@ gst_play_set_uri (GstPlay *play, const guchar *uri)
        if (priv->uri)
                g_free (priv->uri);
 
-       priv->uri = g_strdup (uri);
 
-       priv->src = gst_elementfactory_make ("disksrc", "disk_src");
-       //priv->src = gst_elementfactory_make ("dvdsrc", "disk_src");
-       priv->offset_element = priv->src;
+       /* see if it looks like a ARI */
+       if ((uriloc = strstr (uri, ":/"))) {
+         priv->src = gst_elementfactory_make ("gnomevfssrc", "srcelement");
 
-       g_return_val_if_fail (priv->src != NULL, -1);
-       gtk_object_set (GTK_OBJECT (priv->src), "location", uri, NULL);
+         if (!priv->src) {
+           if (strstr (uri, "file:/")) {
+             uri += strlen ("file:/");
+           }
+           else
+             return GST_PLAY_CANNOT_PLAY;
+         }
+       }
 
-       gst_bin_add (GST_BIN (priv->bin), priv->src);
+       if (priv->src == NULL) {
+         priv->src = gst_elementfactory_make ("disksrc", "srcelement");
+       }
 
-       src_caps = gst_play_typefind (GST_BIN (priv->bin), priv->src);
+       priv->uri = g_strdup (uri);
 
-       if (!src_caps) {
-               return GST_PLAY_UNKNOWN_MEDIA;
-       }
+       //priv->src = gst_elementfactory_make ("dvdsrc", "disk_src");
+       priv->offset_element = priv->src;
+       g_return_val_if_fail (priv->src != NULL, GST_PLAY_CANNOT_PLAY);
 
-       autoplug = gst_autoplugfactory_make ("staticrender");
-       g_assert (autoplug != NULL);
+       gtk_object_set (GTK_OBJECT (priv->src), "location", priv->uri, NULL);
 
-       gtk_signal_connect (GTK_OBJECT (autoplug), "new_object", gst_play_object_added, play);
 
-       new_element = gst_autoplug_to_renderers (autoplug,
-                                                gst_pad_get_caps (gst_element_get_pad (priv->src, "src")),
-                                                priv->video_element,
-                                                priv->audio_element,
-                                                NULL);
+       priv->cache = gst_elementfactory_make ("autoplugcache", "cache");
+       g_return_val_if_fail (priv->cache != NULL, GST_PLAY_CANNOT_PLAY);
 
-       if (!new_element) {
-               return GST_PLAY_CANNOT_PLAY;
-       }
+       gtk_signal_connect (GTK_OBJECT (priv->cache), "cache_empty", 
+                       GTK_SIGNAL_FUNC (gst_play_cache_empty), play);
 
-       gst_bin_remove (GST_BIN (priv->bin), priv->src);
-       gst_bin_add (GST_BIN (priv->thread), priv->src);
+       priv->typefind = gst_elementfactory_make ("typefind", "typefind");
+       g_return_val_if_fail (priv->typefind != NULL, GST_PLAY_CANNOT_PLAY);
+       gtk_signal_connect (GTK_OBJECT (priv->typefind), "have_type", 
+                               GTK_SIGNAL_FUNC (gst_play_have_type), play);
 
-       gst_bin_add (GST_BIN (priv->bin), new_element);
 
-       gst_element_connect (priv->src, "src", new_element, "sink");
+       gst_bin_add (GST_BIN (priv->pipeline), priv->src);
+       gst_bin_add (GST_BIN (priv->pipeline), priv->cache);
+       gst_bin_add (GST_BIN (priv->pipeline), priv->typefind);
 
-       gst_bin_add (GST_BIN (priv->thread), priv->bin);
-       gtk_signal_connect (GTK_OBJECT (priv->thread), "eos", GTK_SIGNAL_FUNC (gst_play_eos), play);
+       gst_element_connect (priv->src, "src", priv->cache, "sink");
+       gst_element_connect (priv->cache, "src", priv->typefind, "sink");
 
        return GST_PLAY_OK;
 }
@@ -449,10 +472,11 @@ gst_play_play (GstPlay *play)
        if (play->state == GST_PLAY_PLAYING) return;
 
        if (play->state == GST_PLAY_STOPPED)
-               gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_READY);
-       gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_PLAYING);
+               gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_READY);
+       gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_PLAYING);
 
        play->state = GST_PLAY_PLAYING;
+       gtk_idle_add (gst_play_idle_func, priv->pipeline);
 
        gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
                         play->state);
@@ -470,9 +494,10 @@ gst_play_pause (GstPlay *play)
 
        if (play->state != GST_PLAY_PLAYING) return;
 
-       gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_PAUSED);
+       gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_PAUSED);
 
        play->state = GST_PLAY_PAUSED;
+       g_idle_remove_by_data (priv->pipeline);
 
        gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
                         play->state);
@@ -491,11 +516,12 @@ gst_play_stop (GstPlay *play)
        priv = (GstPlayPrivate *)play->priv;
 
        // FIXME until state changes are handled properly
-       gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_READY);
+       gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_READY);
        gtk_object_set (GTK_OBJECT (priv->src),"offset",0,NULL);
-       //gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_NULL);
+       //gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_NULL);
 
        play->state = GST_PLAY_STOPPED;
+       g_idle_remove_by_data (priv->pipeline);
 
        gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
                         play->state);
@@ -653,7 +679,7 @@ gst_play_get_pipeline (GstPlay *play)
 
        priv = (GstPlayPrivate *)play->priv;
 
-       return GST_ELEMENT (priv->bin);
+       return GST_ELEMENT (priv->pipeline);
 }
 
 static void
index beda5f1..8356dd1 100644 (file)
@@ -19,10 +19,10 @@ typedef enum {
 } GstPlayState;
 
 typedef enum {
-       GST_PLAY_OK,
-       GST_PLAY_UNKNOWN_MEDIA,
-       GST_PLAY_CANNOT_PLAY,
-       GST_PLAY_ERROR,
+  GST_PLAY_OK,
+  GST_PLAY_UNKNOWN_MEDIA,
+  GST_PLAY_CANNOT_PLAY,
+  GST_PLAY_ERROR,
 } GstPlayReturn;
 
 typedef enum {
index 763f80a..2b80f17 100644 (file)
@@ -6,12 +6,13 @@
 typedef struct _GstPlayPrivate GstPlayPrivate;
 
 struct _GstPlayPrivate {
-       GstElement *thread;
-       GstElement *bin;
+       GstElement *pipeline;
        GstElement *video_element, *audio_element;
        GstElement *video_show;
        GtkWidget  *video_widget;
        GstElement *src;
+       GstElement *cache;
+       GstElement *typefind;
        
        guchar *uri;
        gboolean muted;
diff --git a/gstreamer-uninstalled.pc.in b/gstreamer-uninstalled.pc.in
new file mode 100644 (file)
index 0000000..0cc88fd
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: GStreamer Uninstalled
+Description: Streaming-media framework, Not Installed
+Version: @VERSION@
+Requires: glib gtk+
+Libs:  ${pcbuilddir}/${pcfiledir}/gst/libgst.la
+Cflags: -I${pcbuilddir}/${pcfiledir}
diff --git a/gstreamer.pc.in b/gstreamer.pc.in
new file mode 100644 (file)
index 0000000..47ed44b
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: GStreamer
+Description: Streaming-media framework
+Requires:
+Version: @VERSION@
+Libs: -L${libdir} -lgst
+Cflags:
index 28456b1..6ccff3e 100644 (file)
@@ -84,3 +84,4 @@ make prefix=$RPM_BUILD_ROOT%{prefix} install
 %{prefix}/include/*
 %{prefix}/lib/lib*.a
 %{prefix}/lib/lib*.so
+%{prefix}/lib/pkgconfig/*
index 39b3cfc..ae180e3 100644 (file)
@@ -53,38 +53,38 @@ GstIDCT *gst_idct_new(GstIDCTMethod method)
 
   switch (method) {
         case GST_IDCT_FAST_INT:
-               GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using fast_int_idct\n");
+               GST_INFO (GST_CAT_PLUGIN_INFO, "using fast_int_idct");
           gst_idct_init_fast_int_idct();
                new->convert = gst_idct_fast_int_idct;
                break;
         case GST_IDCT_INT:
-               GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using int_idct\n");
+               GST_INFO (GST_CAT_PLUGIN_INFO, "using int_idct");
                new->convert = gst_idct_int_idct;
                break;
         case GST_IDCT_FLOAT:
-               GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using float_idct\n");
+               GST_INFO (GST_CAT_PLUGIN_INFO, "using float_idct");
                gst_idct_init_float_idct();
                new->convert = gst_idct_float_idct;
                break;
 #ifdef HAVE_LIBMMX
         case GST_IDCT_MMX:
-               GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using MMX_idct\n");
+               GST_INFO (GST_CAT_PLUGIN_INFO, "using MMX_idct");
                new->convert = gst_idct_mmx_idct;
                new->need_transpose = TRUE;
                break;
         case GST_IDCT_MMX32:
-               GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using MMX32_idct\n");
+               GST_INFO (GST_CAT_PLUGIN_INFO, "using MMX32_idct");
                new->convert = gst_idct_mmx32_idct;
                new->need_transpose = TRUE;
                break;
         case GST_IDCT_SSE:
-               GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using SSE_idct\n");
+               GST_INFO (GST_CAT_PLUGIN_INFO, "using SSE_idct");
                new->convert = gst_idct_sse_idct;
                new->need_transpose = TRUE;
                break;
 #endif /* HAVE_LIBMMX */
         default:
-               GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: method not supported\n");
+               GST_INFO (GST_CAT_PLUGIN_INFO, "method not supported");
                g_free(new);
                return NULL;
   }
index 5fa6af2..97570bb 100644 (file)
@@ -49,6 +49,7 @@ enum {
   ARG_OUTPUT,
   ARG_PATTERN,
   ARG_NUM_BUFFERS,
+  ARG_EOS,
   ARG_SILENT
 };
 
@@ -125,6 +126,8 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
                            GTK_ARG_READWRITE, ARG_PATTERN);
   gtk_object_add_arg_type ("GstFakeSrc::num_buffers", GTK_TYPE_INT,
                            GTK_ARG_READWRITE, ARG_NUM_BUFFERS);
+  gtk_object_add_arg_type ("GstFakeSrc::eos", GTK_TYPE_BOOL,
+                           GTK_ARG_READWRITE, ARG_EOS);
   gtk_object_add_arg_type ("GstFakeSrc::silent", GTK_TYPE_BOOL,
                            GTK_ARG_READWRITE, ARG_SILENT);
 
@@ -222,6 +225,10 @@ gst_fakesrc_set_arg (GtkObject *object, GtkArg *arg, guint id)
     case ARG_NUM_BUFFERS:
       src->num_buffers = GTK_VALUE_INT (*arg);
       break;
+    case ARG_EOS:
+      src->eos = GTK_VALUE_BOOL (*arg);
+GST_INFO (0, "will EOS on next buffer");
+      break;
     case ARG_SILENT:
       src->silent = GTK_VALUE_BOOL (*arg);
       break;
@@ -256,6 +263,8 @@ gst_fakesrc_get_arg (GtkObject *object, GtkArg *arg, guint id)
     case ARG_NUM_BUFFERS:
       GTK_VALUE_INT (*arg) = src->num_buffers;
       break;
+    case ARG_EOS:
+      GTK_VALUE_BOOL (*arg) = src->eos;
     case ARG_SILENT:
       GTK_VALUE_BOOL (*arg) = src->silent;
       break;
@@ -295,6 +304,12 @@ gst_fakesrc_get(GstPad *pad)
       src->num_buffers--;
   }
 
+  if (src->eos) {
+    GST_INFO (0, "fakesrc is setting eos on pad");
+    gst_pad_set_eos (pad);
+    return NULL;
+  }
+
   if (!src->silent)
     g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad));
   buf = gst_buffer_new();
@@ -336,7 +351,13 @@ gst_fakesrc_loop(GstElement *element)
       }
       else {
       if (src->num_buffers > 0)
-        src->num_buffers--;
+         src->num_buffers--;
+      }
+
+      if (src->eos) {
+        GST_INFO (0, "fakesrc is setting eos on pad");
+        gst_pad_set_eos (pad);
+        return;
       }
 
       buf = gst_buffer_new();
index a795c19..ba92f63 100644 (file)
@@ -65,6 +65,7 @@ struct _GstFakeSrc {
   GstElement element;
 
   gboolean loop_based;
+  gboolean eos;
   gint numsrcpads;
   GSList *srcpads;
   GstFakeSrcOutputType output;
index 37a4f7f..755c8f8 100644 (file)
@@ -23,7 +23,7 @@
 //#define DEBUG_ENABLED
 //#define STATUS_ENABLED
 #ifdef STATUS_ENABLED
-#define STATUS(A) GST_DEBUG(0,A, gst_element_get_name(GST_ELEMENT(queue)))
+#define STATUS(A) GST_DEBUG(GST_CAT_DATAFLOW, A, GST_ELEMENT_NAME(queue))
 #else
 #define STATUS(A)
 #endif
@@ -34,6 +34,7 @@
 #include "gst_private.h"
 
 #include "gstqueue.h"
+#include "gstscheduler.h"
 
 GstElementDetails gst_queue_details = {
   "Queue",
@@ -47,15 +48,22 @@ GstElementDetails gst_queue_details = {
 
 /* Queue signals and args */
 enum {
-  /* FILL ME */
+  LOW_WATERMARK,
+  HIGH_WATERMARK,
   LAST_SIGNAL
 };
 
 enum {
   ARG_0,
+  ARG_LEVEL_BUFFERS,
+  ARG_LEVEL_BYTES,
+  ARG_LEVEL_TIME,
+  ARG_SIZE_BUFFERS,
+  ARG_SIZE_BYTES,
+  ARG_SIZE_TIME,
+  ARG_LEAKY,
   ARG_LEVEL,
   ARG_MAX_LEVEL,
-  ARG_BLOCK,
 };
 
 
@@ -76,6 +84,23 @@ static void                  gst_queue_flush         (GstQueue *queue);
 
 static GstElementStateReturn   gst_queue_change_state  (GstElement *element);
 
+  
+static GtkType
+queue_leaky_get_type(void) {
+  static GtkType queue_leaky_type = 0;
+  static GtkEnumValue queue_leaky[] = {
+    { GST_QUEUE_NO_LEAK, "0", "Not Leaky" },
+    { GST_QUEUE_LEAK_UPSTREAM, "1", "Leaky on Upstream" },
+    { GST_QUEUE_LEAK_DOWNSTREAM, "2", "Leaky on Downstream" },
+    { 0, NULL, NULL },
+  };
+  if (!queue_leaky_type) {
+    queue_leaky_type = gtk_type_register_enum("GstQueueLeaky", queue_leaky);
+  }
+  return queue_leaky_type;
+}
+#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type())
+
 
 static GstElementClass *parent_class = NULL;
 //static guint gst_queue_signals[LAST_SIGNAL] = { 0 };
@@ -111,12 +136,12 @@ gst_queue_class_init (GstQueueClass *klass)
 
   parent_class = gtk_type_class (GST_TYPE_ELEMENT);
 
+  gtk_object_add_arg_type ("GstQueue::leaky", GST_TYPE_QUEUE_LEAKY,
+                           GTK_ARG_READWRITE, ARG_LEAKY);
   gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT,
                            GTK_ARG_READABLE, ARG_LEVEL);
   gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT,
                            GTK_ARG_READWRITE, ARG_MAX_LEVEL);
-  gtk_object_add_arg_type ("GstQueue::block", GTK_TYPE_BOOL,
-                           GTK_ARG_READWRITE, ARG_BLOCK);
 
   gtkobject_class->set_arg = gst_queue_set_arg;
   gtkobject_class->get_arg = gst_queue_get_arg;
@@ -144,14 +169,15 @@ gst_queue_init (GstQueue *queue)
 
   queue->queue = NULL;
   queue->level_buffers = 0;
-  queue->max_buffers = 100;
-  queue->block = TRUE;
   queue->level_bytes = 0;
-  queue->size_buffers = 0;
-  queue->size_bytes = 0;
+  queue->level_time = 0LL;
+  queue->size_buffers = 100;           // 100 buffers
+  queue->size_bytes = 100 * 1024;      // 100KB
+  queue->size_time = 1000000000LL;     // 1sec
 
   queue->emptycond = g_cond_new ();
   queue->fullcond = g_cond_new ();
+  GST_DEBUG(GST_CAT_THREAD, "initialized queue's emptycond and fullcond\n");
 }
 
 static GstBufferPool*
@@ -206,10 +232,10 @@ gst_queue_handle_eos (GstPad *pad)
 
   queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
 
-  GST_DEBUG (0,"queue: %s received eos\n", GST_ELEMENT_NAME (queue));
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s received eos\n", GST_ELEMENT_NAME (queue));
 
   GST_LOCK (queue);
-  GST_DEBUG (0,"queue: %s has %d buffers left\n", GST_ELEMENT_NAME (queue),
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s has %d buffers left\n", GST_ELEMENT_NAME (queue),
                  queue->level_buffers);
 
   GST_FLAG_SET (pad, GST_PAD_EOS);
@@ -224,7 +250,7 @@ gst_queue_handle_eos (GstPad *pad)
 static void
 gst_queue_cleanup_buffers (gpointer data, const gpointer user_data)
 {
-  GST_DEBUG (0,"queue: %s cleaning buffer %p\n", (gchar *)user_data, data);
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s cleaning buffer %p\n", (gchar *)user_data, data);
 
   gst_buffer_unref (GST_BUFFER (data));
 }
@@ -257,45 +283,79 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf)
 
   /* we have to lock the queue since we span threads */
 
-  GST_DEBUG (0,"queue: try have queue lock\n");
+//  GST_DEBUG (GST_CAT_DATAFLOW,"trying to get lock on queue \"%s\"\n",name);
   GST_LOCK (queue);
-  GST_DEBUG (0,"queue: %s adding buffer %p %ld\n", name, buf, pthread_self ());
-  GST_DEBUG (0,"queue: have queue lock\n");
 
   if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) {
+    GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "buffer has FLUSH bit set, flushing queue\n");
     gst_queue_flush (queue);
   }
 
-  GST_DEBUG (0,"queue: %s: chain %d %p\n", name, queue->level_buffers, buf);
+  GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "adding buffer %p of size %d\n",buf,GST_BUFFER_SIZE(buf));
+
+  if (queue->level_buffers >= queue->size_buffers) {
+    // if this is a leaky queue...
+    if (queue->leaky) {
+      // if we leak on the upstream side, drop the current buffer
+      if (queue->leaky == GST_QUEUE_LEAK_UPSTREAM) {
+        GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on upstream end\n");
+        gst_buffer_unref(buf);
+        // now we have to clean up and exit right away
+        GST_UNLOCK (queue);
+        return;
+      }
+      // otherwise we have to push a buffer off the other end
+      else {
+        GSList *front;
+        GstBuffer *leakbuf;
+        GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end\n");
+        front = queue->queue;
+        leakbuf = (GstBuffer *)(front->data);
+        queue->level_buffers--;
+        queue->level_bytes -= GST_BUFFER_SIZE(leakbuf);
+        gst_buffer_unref(leakbuf);
+        queue->queue = g_slist_remove_link (queue->queue, front);
+        g_slist_free (front);
+      }
+    }
 
-  while (queue->level_buffers >= queue->max_buffers) {
-    GST_DEBUG (0,"queue: %s waiting %d\n", name, queue->level_buffers);
-    STATUS("%s: O\n");
-    //g_cond_timed_wait (queue->fullcond, queue->fulllock, queue->timeval);
-    //FIXME need to signal other thread in case signals got lost?
-    g_cond_signal (queue->emptycond);
-    g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock);
-    STATUS("%s: O+\n");
-    GST_DEBUG (0,"queue: %s waiting done %d\n", name, queue->level_buffers);
+    while (queue->level_buffers >= queue->size_buffers) {
+      // if there's a pending state change for this queue or its manager, switch
+      // back to iterator so bottom half of state change executes
+      if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
+//          GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
+GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->sinkpad))))) != 
+GST_STATE_NONE_PENDING)
+      {
+        GST_DEBUG(GST_CAT_DATAFLOW,"interrupted!!\n");
+        if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)
+          GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)\n");
+        if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
+          GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING\n");
+        GST_UNLOCK(queue);
+        cothread_switch(cothread_current_main());
+      }
+
+      GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for space, level is %d\n", queue->level_buffers);
+      g_cond_signal (queue->emptycond);
+      g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock);
+      GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "done waiting, level is now %d\n", queue->level_buffers);
+    }
   }
 
   /* put the buffer on the tail of the list */
   queue->queue = g_slist_append (queue->queue, buf);
-//  STATUS("%s: +\n");
-  GST_DEBUG (0,"(%s:%s)+ ",GST_DEBUG_PAD_NAME(pad));
-
-  /* if we were empty, but aren't any more, signal a condition */
-  tosignal = (queue->level_buffers >= 0);
   queue->level_buffers++;
+  queue->level_bytes += GST_BUFFER_SIZE(buf);
+//  GST_DEBUG (GST_CAT_DATAFLOW, "(%s:%s)+\n",GST_DEBUG_PAD_NAME(pad));
 
-  /* we can unlock now */
-  GST_DEBUG (0,"queue: %s chain %d end signal(%d,%p)\n", name, queue->level_buffers, tosignal, queue->emptycond);
-
-  if (tosignal) {
-//    STATUS("%s: >\n");
+  /* if we were empty, but aren't any more, signal a condition */
+  if (queue->level_buffers == 1)
+  {
+    GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling emptycond\n", name);
     g_cond_signal (queue->emptycond);
-//    STATUS("%s: >>\n");
   }
+
   GST_UNLOCK (queue);
 }
 
@@ -307,6 +367,8 @@ gst_queue_get (GstPad *pad)
   GSList *front;
   const guchar *name;
 
+  g_assert(pad != NULL);
+  g_assert(GST_IS_PAD(pad));
   g_return_val_if_fail (pad != NULL, NULL);
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
@@ -314,63 +376,74 @@ gst_queue_get (GstPad *pad)
   name = GST_ELEMENT_NAME (queue);
 
   /* have to lock for thread-safety */
-  GST_DEBUG (0,"queue: %s try have queue lock\n", name);
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s try have queue lock\n", name);
   GST_LOCK (queue);
-  GST_DEBUG (0,"queue: %s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
-  GST_DEBUG (0,"queue: %s have queue lock\n", name);
-
-  // we bail if there's nothing there
-  if (!queue->level_buffers && !queue->block) {
-    GST_UNLOCK(queue);
-    return NULL;
-  }
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
+  GST_DEBUG (GST_CAT_DATAFLOW,"%s have queue lock\n", name);
 
   while (!queue->level_buffers) {
-    STATUS("queue: %s U released lock\n");
-    //g_cond_timed_wait (queue->emptycond, queue->emptylock, queue->timeval);
     if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) {
+      GST_DEBUG (GST_CAT_DATAFLOW, "%s U released lock\n", name);
+      GST_UNLOCK(queue);
       gst_pad_set_eos (queue->srcpad);
+      // this return NULL shouldn't hurt anything...
       return NULL;
     }
-    //FIXME need to signal other thread in case signals got lost?
+
+    // if there's a pending state change for this queue or its manager, switch
+    // back to iterator so bottom half of state change executes
+    if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
+//        GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
+GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->srcpad))))) != 
+GST_STATE_NONE_PENDING)
+    {
+      GST_DEBUG(GST_CAT_DATAFLOW,"interrupted!!\n");
+      if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)
+        GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)\n");
+      if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
+        GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING\n");
+      GST_UNLOCK(queue);
+      cothread_switch(cothread_current_main());
+    }
+
     g_cond_signal (queue->fullcond);
     g_cond_wait (queue->emptycond, GST_OBJECT(queue)->lock);
-//    STATUS("queue: %s U- getting lock\n");
   }
 
   front = queue->queue;
   buf = (GstBuffer *)(front->data);
-  GST_DEBUG (0,"retrieved buffer %p from queue\n",buf);
+  GST_DEBUG (GST_CAT_DATAFLOW,"retrieved buffer %p from queue\n",buf);
   queue->queue = g_slist_remove_link (queue->queue, front);
   g_slist_free (front);
 
-  queue->level_buffers--;
-//  STATUS("%s: -\n");
-  GST_DEBUG (0,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
-
-  if (queue->level_buffers < queue->max_buffers) {
-//    STATUS("%s: < \n");
+//  if (queue->level_buffers < queue->size_buffers)
+  if (queue->level_buffers == queue->size_buffers)
+  {
+    GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling fullcond\n", name);
     g_cond_signal (queue->fullcond);
-//    STATUS("%s: << \n");
   }
-  GST_UNLOCK(queue);
 
-//  GST_DEBUG (0,"queue: %s pushing %d %p \n", name, queue->level_buffers, buf);
-//  gst_pad_push (queue->srcpad, buf);
-//  GST_DEBUG (0,"queue: %s pushing %d done \n", name, queue->level_buffers);
+  queue->level_buffers--;
+  queue->level_bytes -= GST_BUFFER_SIZE(buf);
+  GST_DEBUG (GST_CAT_DATAFLOW,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
+
+  GST_UNLOCK(queue);
 
   return buf;
-  /* unlock now */
 }
 
 static GstElementStateReturn
 gst_queue_change_state (GstElement *element)
 {
   GstQueue *queue;
+  GstElementStateReturn ret;
   g_return_val_if_fail (GST_IS_QUEUE (element), GST_STATE_FAILURE);
 
   queue = GST_QUEUE (element);
-  GST_DEBUG (0,"gstqueue: state pending %d\n", GST_STATE_PENDING (element));
+
+  // lock the queue so another thread (not in sync with this thread's state)
+  // can't call this queue's _get (or whatever)
+  GST_LOCK (queue);
 
   /* if going down into NULL state, clear out buffers*/
   if (GST_STATE_PENDING (element) == GST_STATE_READY) {
@@ -380,9 +453,41 @@ gst_queue_change_state (GstElement *element)
 
   /* if we haven't failed already, give the parent class a chance to ;-) */
   if (GST_ELEMENT_CLASS (parent_class)->change_state)
-    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+  {
+    gboolean valid_handler = FALSE;
+    guint state_change_id = gtk_signal_lookup("state_change", GTK_OBJECT_TYPE(element));
+
+    // determine whether we need to block the parent (element) class'
+    // STATE_CHANGE signal so we can UNLOCK before returning.  we block
+    // it if we could find the state_change signal AND there's a signal
+    // handler attached to it.
+    //
+    // note: this assumes that change_state() *only* emits state_change signal.
+    // if element change_state() emits other signals, they need to be blocked
+    // as well.
+    if (state_change_id &&
+        gtk_signal_handler_pending(GTK_OBJECT(element), state_change_id, FALSE))
+      valid_handler = TRUE;
+    if (valid_handler)
+      gtk_signal_handler_block(GTK_OBJECT(element), state_change_id);
+
+    ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+    if (valid_handler)
+      gtk_signal_handler_unblock(GTK_OBJECT(element), state_change_id);
+
+    // UNLOCK, *then* emit signal (if there's one there)
+    GST_UNLOCK(queue);
+    if (valid_handler)
+      gtk_signal_emit(GTK_OBJECT (element), state_change_id, GST_STATE(element));
+  }
+  else
+  {
+    ret = GST_STATE_SUCCESS;
+    GST_UNLOCK(queue);
+  }
 
-  return GST_STATE_SUCCESS;
+  return ret;
 }
 
 
@@ -397,11 +502,11 @@ gst_queue_set_arg (GtkObject *object, GtkArg *arg, guint id)
   queue = GST_QUEUE (object);
 
   switch(id) {
-    case ARG_MAX_LEVEL:
-      queue->max_buffers = GTK_VALUE_INT (*arg);
+    case ARG_LEAKY:
+      queue->leaky = GTK_VALUE_INT (*arg);
       break;
-    case ARG_BLOCK:
-      queue->block = GTK_VALUE_BOOL (*arg);
+    case ARG_MAX_LEVEL:
+      queue->size_buffers = GTK_VALUE_INT (*arg);
       break;
     default:
       break;
@@ -419,14 +524,14 @@ gst_queue_get_arg (GtkObject *object, GtkArg *arg, guint id)
   queue = GST_QUEUE (object);
 
   switch (id) {
+    case ARG_LEAKY:
+      GTK_VALUE_INT (*arg) = queue->leaky;
+      break;
     case ARG_LEVEL:
       GTK_VALUE_INT (*arg) = queue->level_buffers;
       break;
     case ARG_MAX_LEVEL:
-      GTK_VALUE_INT (*arg) = queue->max_buffers;
-      break;
-    case ARG_BLOCK:
-      GTK_VALUE_BOOL (*arg) = queue->block;
+      GTK_VALUE_INT (*arg) = queue->size_buffers;
       break;
     default:
       arg->type = GTK_TYPE_INVALID;
index 6063467..085d5ac 100644 (file)
@@ -47,6 +47,12 @@ GstElementDetails gst_queue_details;
 #define GST_IS_QUEUE_CLASS(obj) \
   (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
 
+enum {
+  GST_QUEUE_NO_LEAK            = 0,
+  GST_QUEUE_LEAK_UPSTREAM      = 1,
+  GST_QUEUE_LEAK_DOWNSTREAM    = 2
+};
+
 typedef struct _GstQueue GstQueue;
 typedef struct _GstQueueClass GstQueueClass;
 
@@ -60,12 +66,16 @@ struct _GstQueue {
   GSList *queue;
 
   gint level_buffers;  /* number of buffers queued here */
-  gint max_buffers;    /* maximum number of buffers queued here */
-  gboolean block;      /* if set to FALSE, _get returns NULL if queue empty */
   gint level_bytes;    /* number of bytes queued here */
+  guint64 level_time;  /* amount of time queued here */
+
   gint size_buffers;   /* size of queue in buffers */
   gint size_bytes;     /* size of queue in bytes */
+  guint64 size_time;   /* size of queue in time */
 
+  gint leaky;          /* whether the queue is leaky, and if so at which end */
+
+//  GMutex *lock;      (optimization?)
   GCond *emptycond;
   GCond *fullcond;
 
@@ -74,6 +84,10 @@ struct _GstQueue {
 
 struct _GstQueueClass {
   GstElementClass parent_class;
+
+  /* signal callbacks */
+  void (*low_watermark)                (GstQueue *queue, gint level);
+  void (*high_watermark)       (GstQueue *queue, gint level);
 };
 
 GtkType gst_queue_get_type (void);
index 8cddd5d..6a00e1e 100644 (file)
@@ -407,4 +407,4 @@ gst_sinesrc_factory_init (GstElementFactory *factory)
   gst_elementfactory_add_padtemplate (factory, src_temp);
   
   return TRUE;
-}
\ No newline at end of file
+}
index 81021e4..89626b4 100644 (file)
@@ -29,6 +29,7 @@ mp3parse
 mpeg2parse
 mpeg2parse2
 mpeg2parse3
+mpeg2parse4
 mp3play
 ac3parse
 ac3play
index ea89a6a..50f7a8f 100644 (file)
@@ -22,18 +22,6 @@ ac3play_SOURCES = ac3play.c mem.c
 
 noinst_HEADERS = mem.h
 
-if HAVE_LIBXV
-xvlibs=-lXv
-else
-xvlibs=
-endif
-
-LDADD = ${xvlibs} -lXxf86vm $(GNOME_LIBS) $(GST_LIBS)
-
-#LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la \
-#          $(top_builddir)/plugins/videosink/libvideosink.la -L/usr/X11/lib -lXxf86dga
-#LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la
-
 LIBS += $(GNOME_LIBS) $(GST_LIBS)
 CFLAGS += $(GNOME_CFLAGS) $(GST_CFLAGS)
 
index 8661629..1d64a9a 100644 (file)
@@ -141,7 +141,7 @@ int main(int argc,char *argv[]) {
   g_return_val_if_fail(src != NULL, -1);
   gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
   g_print("should be using file '%s'\n",argv[1]);
-  parse = gst_elementfactory_make("parseavi","parse");
+  parse = gst_elementfactory_make("avidecoder","parse");
   g_return_val_if_fail(parse != NULL, -1);
 
   mux = gst_elementfactory_make("system_encode","mux");
index 7f96309..3f45ca4 100644 (file)
@@ -32,8 +32,6 @@ int main(int argc,char *argv[]) {
   gst_pad_connect(gst_element_get_pad(identity,"src"),
                  gst_element_get_pad(sink,"sink"));
 
-  g_print("--- creating a plan\n");
-  gst_bin_create_plan(GST_BIN(bin));
 
   g_print("--- starting up\n");
   gst_bin_iterate(GST_BIN(bin));
index 45fc498..b6b462a 100644 (file)
@@ -29,7 +29,7 @@ main (int argc,char *argv[])
 
   gnome_init("Videotest","0.0.1",argc,argv);
 
-  bin = gst_bin_new("bin");
+  bin = gst_pipeline_new("pipeline");
 
   if (argc == 1) {
     src = gst_elementfactory_make ("dv1394src", "src");
index d24efa9..2910d94 100644 (file)
@@ -10,7 +10,7 @@ int main(int argc,char *argv[]) {
 //  _gst_plugin_spew = TRUE;
   gst_init(&argc,&argv);
 
-  bin = gst_bin_new("bin");
+  bin = gst_pipeline_new("pipeline");
   g_return_if_fail(bin != NULL);
 
   g_print("--- creating src and sink elements\n");
@@ -35,8 +35,6 @@ int main(int argc,char *argv[]) {
   g_print("--- setting up\n");
   gst_element_set_state(GST_ELEMENT(bin),GST_STATE_READY);
 
-  g_print("--- creating plan\n");
-  gst_bin_create_plan(bin);
   g_print("--- iterating\n");
   gst_bin_iterate(bin);
 }
index 176eed3..75a04c4 100644 (file)
@@ -86,6 +86,7 @@ int main(int argc,char *argv[]) {
 
   gtk_socket = gtk_socket_new ();
   gtk_widget_show (gtk_socket);
+  gtk_widget_set_usize(gtk_socket,320,240);
 
   gnome_app_set_contents(GNOME_APP(appwindow),
                GTK_WIDGET(gtk_socket));
index ee2e3d8..c74aacf 100644 (file)
@@ -1,8 +1,10 @@
 #include <gnome.h>
 #include <gst/gst.h>
 
-GstElement *parse2, *v_queue, *a_queue;
+GstPipeline *pipeline;
+GstElement *v_queue, *a_queue, *v_thread, *a_thread;
 GtkWidget *appwindow;
+GtkWidget  *gtk_socket;
 
 void eof(GstElement *src) {
   g_print("have eos, quitting\n");
@@ -17,38 +19,37 @@ gboolean idle_func(gpointer data) {
 void mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) {
 
   g_print("***** a new pad %s was created\n", gst_pad_get_name(pad));
-  gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PAUSED);
 
   if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) {
     gst_pad_connect(pad, gst_element_get_pad(v_queue,"sink"));
+    gst_bin_add(GST_BIN(pipeline),v_thread);
+    gst_element_set_state(v_thread,GST_STATE_PLAYING);
   } else if (strcmp(gst_pad_get_name(pad), "private_stream_1.0") == 0) {
     gst_pad_connect(pad, gst_element_get_pad(a_queue,"sink"));
+    gst_bin_add(GST_BIN(pipeline),a_thread);
+    gst_element_set_state(a_thread,GST_STATE_PLAYING);
   }
-  gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
+}
+
+void mpeg2parse_have_size(GstElement *videosink,gint width,gint height) {
+  gtk_widget_set_usize(gtk_socket,width,height);
+  gtk_widget_show_all(appwindow);
 }
 
 int main(int argc,char *argv[]) {
-  GstPipeline *pipeline;
   GstElement *src, *parse;
-  GstElement *v_thread, *v_decode, *show, *color;
-  GstElement *a_thread, *a_decode, *osssink;
-  GtkWidget  *gtk_socket;
+  GstElement *v_decode, *show, *color;
+  GstElement *a_decode, *osssink;
 
   g_print("have %d args\n",argc);
 
   gst_init(&argc,&argv);
   gnome_init("MPEG2 Video player","0.0.1",argc,argv);
-  //gst_plugin_load("mpeg1parse");
 
+  // ***** construct the main pipeline *****
   pipeline = GST_PIPELINE(gst_pipeline_new("pipeline"));
   g_return_val_if_fail(pipeline != NULL, -1);
 
-  v_thread = GST_ELEMENT(gst_thread_new("v_thread"));
-  g_return_val_if_fail(v_thread != NULL, -1);
-
-  a_thread = GST_ELEMENT(gst_thread_new("a_thread"));
-  g_return_val_if_fail(a_thread != NULL, -1);
-
   if (strstr(argv[1],"video_ts")) {
     src = gst_elementfactory_make("dvdsrc","src");
     g_print("using DVD source\n");
@@ -68,20 +69,19 @@ int main(int argc,char *argv[]) {
   //parse = gst_elementfactory_make("mpeg1parse","parse");
   g_return_val_if_fail(parse != NULL, -1);
 
+  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
+  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
+
+  gst_element_connect(src,"src",parse,"sink");
+
+
+  // ***** pre-construct the video thread *****
+  v_thread = GST_ELEMENT(gst_thread_new("v_thread"));
+  g_return_val_if_fail(v_thread != NULL, -1);
+
   v_queue = gst_elementfactory_make("queue","v_queue");
   g_return_val_if_fail(v_queue != NULL, -1);
-  
-  a_queue = gst_elementfactory_make("queue","a_queue");
-  g_return_val_if_fail(a_queue != NULL, -1);
-  
-  /****
-   *  you can substitute mpeg2play with you own player here
-   *  optionally you can remove the parse2 element. make
-   *  sure to remove the pad connections too and don't add the
-   *  mp2videoparse element to the bin.
-   **/
-  //parse2 = gst_elementfactory_make("mp2videoparse","parse");
-  //g_return_val_if_fail(parse2 != NULL, -1);
+
   v_decode = gst_elementfactory_make("mpeg2dec","decode_video");
   g_return_val_if_fail(v_decode != NULL, -1);
 
@@ -89,16 +89,40 @@ int main(int argc,char *argv[]) {
   g_return_val_if_fail(color != NULL, -1);
 
   show = gst_elementfactory_make("xvideosink","show");
-  //show = gst_elementfactory_make("aasink","show");
-  //gtk_object_set(GTK_OBJECT(show),"xv_enabled",FALSE,NULL);
   g_return_val_if_fail(show != NULL, -1);
 
+  gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_queue));
+  gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_decode));
+  gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(color));
+  gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(show));
+
+  gst_element_connect(v_queue,"src",v_decode,"sink");
+  gst_element_connect(v_decode,"src",color,"sink");
+  gst_element_connect(color,"src",show,"sink");
+
+
+  // ***** pre-construct the audio thread *****
+  a_thread = GST_ELEMENT(gst_thread_new("a_thread"));
+  g_return_val_if_fail(a_thread != NULL, -1);
+
+  a_queue = gst_elementfactory_make("queue","a_queue");
+  g_return_val_if_fail(a_queue != NULL, -1);
+  
   a_decode = gst_elementfactory_make("ac3dec","decode_audio");
   g_return_val_if_fail(a_decode != NULL, -1);
 
   osssink = gst_elementfactory_make("osssink","osssink");
   g_return_val_if_fail(osssink != NULL, -1);
 
+  gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_queue));
+  gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_decode));
+  gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(osssink));
+
+  gst_element_connect(a_queue,"src",a_decode,"sink");
+  gst_element_connect(a_decode,"src",osssink,"sink");
+
+
+  // ***** construct the GUI *****
   appwindow = gnome_app_new("MPEG player","MPEG player");
 
   gtk_socket = gtk_socket_new ();
@@ -111,45 +135,9 @@ int main(int argc,char *argv[]) {
   gtk_socket_steal (GTK_SOCKET (gtk_socket), 
                  gst_util_get_int_arg (GTK_OBJECT(show), "xid"));
 
-  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
-  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
-  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(v_queue));
-
-  //gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(parse2));
-  gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_decode));
-  gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(color));
-  gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(show));
-
-  gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_decode));
-  gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(osssink));
-
-  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(v_thread));
-  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(a_thread));
-
   gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad, pipeline);
-
   gtk_signal_connect(GTK_OBJECT(src),"eos",GTK_SIGNAL_FUNC(eof),NULL);
-
-  gst_pad_connect(gst_element_get_pad(src,"src"),
-                  gst_element_get_pad(parse,"sink"));
-
-  // video
-  gst_pad_connect(gst_element_get_pad(v_queue,"src"),
-  //                gst_element_get_pad(parse2,"sink"));
-  //gst_pad_connect(gst_element_get_pad(parse2,"src"),
-                  gst_element_get_pad(v_decode,"sink"));
-  gst_pad_connect(gst_element_get_pad(v_decode,"src"),
-                  gst_element_get_pad(color,"sink"));
-  gst_pad_connect(gst_element_get_pad(color,"src"),
-                  gst_element_get_pad(show,"sink"));
-
-  // audio
-  gst_pad_connect(gst_element_get_pad(a_queue,"src"),
-                  gst_element_get_pad(a_decode,"sink"));
-  gst_pad_connect(gst_element_get_pad(a_decode,"src"),
-                  gst_element_get_pad(osssink,"sink"));
-
-  gtk_widget_show_all(appwindow);
+  gtk_signal_connect(GTK_OBJECT(show),"have_size",mpeg2parse_have_size, pipeline);
 
   g_print("setting to PLAYING state\n");
   gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
diff --git a/test/mpeg2parse4.c b/test/mpeg2parse4.c
new file mode 100644 (file)
index 0000000..f918a11
--- /dev/null
@@ -0,0 +1,224 @@
+#include <gnome.h>
+#include <gst/gst.h>
+
+GstElement *pipeline, *src, *parse;
+GstElement *v_decode_thread, *v_decode_queue, *v_decode, *v_color;
+GstElement *v_show_thread, *v_show_queue, *v_show;
+GstElement *a_decode_thread, *a_decode_queue, *a_decode;
+GstElement *a_sink_thread, *a_sink_queue, *a_sink;
+GtkWidget *appwindow;
+GtkWidget  *gtk_socket;
+
+void eof(GstElement *src) {
+  fprintf(stderr,"have eos, quitting\n");
+  exit(0);
+}
+
+gboolean idle_func(gpointer data) {
+  gst_bin_iterate(GST_BIN(data));
+  return TRUE;
+}
+
+int mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) {
+
+  fprintf(stderr,"***** a new pad %s was created\n", gst_pad_get_name(pad));
+
+  if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) {
+
+    // build the decoder thread
+    v_decode_thread = GST_ELEMENT(gst_thread_new("v_decode_thread"));
+    g_return_val_if_fail(v_decode_thread != NULL, -1);
+
+    v_decode_queue = gst_elementfactory_make("queue","v_decode_queue");
+    g_return_val_if_fail(v_decode_queue != NULL, -1);
+
+    v_decode = gst_elementfactory_make("mpeg2dec","v_decode");
+    g_return_val_if_fail(v_decode != NULL, -1);
+
+    v_color = gst_elementfactory_make("colorspace","v_color");
+    g_return_val_if_fail(v_color != NULL, -1);
+
+    gst_bin_add(GST_BIN(v_decode_thread),GST_ELEMENT(v_decode_queue));
+    gst_bin_add(GST_BIN(v_decode_thread),GST_ELEMENT(v_decode));
+    gst_bin_add(GST_BIN(v_decode_thread),GST_ELEMENT(v_color));
+
+    gst_element_connect(v_decode_queue,"src",v_decode,"sink");
+    gst_element_connect(v_decode,"src",v_color,"sink");
+
+    gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
+
+
+    // build the show thread
+    v_show_thread = GST_ELEMENT(gst_thread_new("v_show_thread"));
+    g_return_val_if_fail(v_show_thread != NULL, -1);
+
+    v_show_queue = gst_elementfactory_make("queue","v_show_queue");
+    g_return_val_if_fail(v_show_queue != NULL, -1);
+
+    // v_show has ben created earlier
+
+    gst_bin_add(GST_BIN(v_show_thread),GST_ELEMENT(v_show_queue));
+    gst_bin_add(GST_BIN(v_show_thread),GST_ELEMENT(v_show));
+
+    gst_element_connect(v_show_queue,"src",v_show,"sink");
+
+
+    // now assemble the decoder threads
+    gst_bin_add(GST_BIN(v_decode_thread),v_show_thread);
+    gst_element_connect(v_color,"src",v_show_queue,"sink");
+
+    gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
+    gst_schedule_show(GST_ELEMENT_SCHED(v_show_thread));
+
+    // connect the whole thing to the main pipeline
+    gst_pad_connect(pad, gst_element_get_pad(v_decode_queue,"sink"));
+    gst_bin_add(GST_BIN(pipeline),v_decode_thread);
+
+    gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
+    gst_schedule_show(GST_ELEMENT_SCHED(v_show_thread));
+
+    // start it playing
+    gst_element_set_state(v_decode_thread,GST_STATE_PLAYING);
+
+  } else if (strcmp(gst_pad_get_name(pad), "private_stream_1.0") == 0) {
+    // build the decoder thread
+    a_decode_thread = GST_ELEMENT(gst_thread_new("a_decode_thread"));
+    g_return_val_if_fail(a_decode_thread != NULL, -1);
+
+    a_decode_queue = gst_elementfactory_make("queue","a_decode_queue");
+    g_return_val_if_fail(a_decode_queue != NULL, -1);
+
+    a_decode = gst_elementfactory_make("ac3dec","a_decode");
+    g_return_val_if_fail(a_decode != NULL, -1);
+
+    gst_bin_add(GST_BIN(a_decode_thread),GST_ELEMENT(a_decode_queue));
+    gst_bin_add(GST_BIN(a_decode_thread),GST_ELEMENT(a_decode));
+
+    gst_element_connect(a_decode_queue,"src",a_decode,"sink");
+
+    gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
+
+
+    // build the sink thread
+    a_sink_thread = GST_ELEMENT(gst_thread_new("a_sink_thread"));
+    g_return_val_if_fail(a_sink_thread != NULL, -1);
+
+    a_sink_queue = gst_elementfactory_make("queue","a_sink_queue");
+    g_return_val_if_fail(a_sink_queue != NULL, -1);
+
+    a_sink = gst_elementfactory_make("esdsink","a_sink");
+    g_return_val_if_fail(a_sink != NULL, -1);
+
+    gst_bin_add(GST_BIN(a_sink_thread),GST_ELEMENT(a_sink_queue));
+    gst_bin_add(GST_BIN(a_sink_thread),GST_ELEMENT(a_sink));
+
+    gst_element_connect(a_sink_queue,"src",a_sink,"sink");
+
+
+    // now assemble the decoder threads
+    gst_bin_add(GST_BIN(a_decode_thread),a_sink_thread);
+    gst_element_connect(a_decode,"src",a_sink_queue,"sink");
+
+    gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
+    gst_schedule_show(GST_ELEMENT_SCHED(a_sink_thread));
+
+    // connect the whole thing to the main pipeline
+    gst_pad_connect(pad, gst_element_get_pad(a_decode_queue,"sink"));
+    gst_bin_add(GST_BIN(pipeline),a_decode_thread);
+
+    gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
+    gst_schedule_show(GST_ELEMENT_SCHED(a_sink_thread));
+
+    // start it playing
+    gst_element_set_state(a_decode_thread,GST_STATE_PLAYING);
+
+  }
+
+  if (v_decode_thread && a_decode_thread) {
+    xmlSaveFile("mpeg2parse4.gst", gst_xml_write(GST_ELEMENT(pipeline)));
+fprintf(stderr,"DUMP OF ALL SCHEDULES!!!:\n");
+    gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
+    gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
+    gst_schedule_show(GST_ELEMENT_SCHED(v_show_thread));
+    gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
+    gst_schedule_show(GST_ELEMENT_SCHED(a_sink_thread));
+  }
+
+  return 0;
+}
+
+void mpeg2parse_have_size(GstElement *videosink,gint width,gint height) {
+  gtk_widget_set_usize(gtk_socket,width,height);
+  gtk_widget_show_all(appwindow);
+}
+
+int main(int argc,char *argv[]) {
+
+  g_print("have %d args\n",argc);
+
+  gst_init(&argc,&argv);
+  gnome_init("MPEG2 Video player","0.0.1",argc,argv);
+
+  // ***** construct the main pipeline *****
+  pipeline = gst_pipeline_new("pipeline");
+  g_return_val_if_fail(pipeline != NULL, -1);
+
+  if (strstr(argv[1],"video_ts")) {
+    src = gst_elementfactory_make("dvdsrc","src");
+    g_print("using DVD source\n");
+  } else {
+    src = gst_elementfactory_make("disksrc","src");
+  }
+
+  g_return_val_if_fail(src != NULL, -1);
+  gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
+  if (argc >= 3) {
+    gtk_object_set(GTK_OBJECT(src),"bytesperread",atoi(argv[2]),NULL);
+    g_print("block size is %d\n",atoi(argv[2]));
+  }
+  g_print("should be using file '%s'\n",argv[1]);
+
+  parse = gst_elementfactory_make("mpeg2parse","parse");
+  //parse = gst_elementfactory_make("mpeg1parse","parse");
+  g_return_val_if_fail(parse != NULL, -1);
+
+  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
+  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
+
+  gst_element_connect(src,"src",parse,"sink");
+
+
+  // create v_show early so we can get and connect stuff
+  v_show = gst_elementfactory_make("xvideosink","v_show");
+  g_return_val_if_fail(v_show != NULL, -1);
+
+
+
+  // ***** construct the GUI *****
+  appwindow = gnome_app_new("MPEG player","MPEG player");
+
+  gtk_socket = gtk_socket_new ();
+  gtk_widget_show (gtk_socket);
+
+  gnome_app_set_contents(GNOME_APP(appwindow),
+               GTK_WIDGET(gtk_socket));
+
+  gtk_widget_realize (gtk_socket);
+  gtk_socket_steal (GTK_SOCKET (gtk_socket), 
+                 gst_util_get_int_arg (GTK_OBJECT(v_show), "xid"));
+
+  gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad, pipeline);
+  gtk_signal_connect(GTK_OBJECT(src),"eos",GTK_SIGNAL_FUNC(eof),NULL);
+  gtk_signal_connect(GTK_OBJECT(v_show),"have_size",mpeg2parse_have_size, pipeline);
+
+  fprintf(stderr,"setting to PLAYING state\n");
+  gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
+
+  gtk_idle_add(idle_func,pipeline);
+
+  gdk_threads_enter();
+  gtk_main();
+  gdk_threads_leave();
+
+  return 0;
+}
index 79b3a50..786f765 100644 (file)
@@ -54,7 +54,6 @@ gst_play_typefind (GstBin *bin, GstElement *element)
   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;
 }
@@ -174,6 +173,7 @@ int main(int argc,char *argv[])
     exit (-1);
   }
 
+  gst_object_ref (GST_OBJECT (disksrc));
   gst_bin_remove (GST_BIN (bin), disksrc);
   gst_object_destroy (GST_OBJECT (bin));
 
index c830cc8..0f69f44 100644 (file)
@@ -27,7 +27,7 @@ main (int argc,char *argv[])
 
   gnome_init("Videotest","0.0.1",argc,argv);
 
-  bin = gst_bin_new("bin");
+  bin = gst_pipeline_new("pipeline");
 
   src = gst_elementfactory_make ("v4lsrc", "src");
   gtk_object_set(GTK_OBJECT(src),"format",9,NULL);
index c30852d..11ce4da 100644 (file)
@@ -1,8 +1,8 @@
-SUBDIRS = sched eos 
+SUBDIRS = sched eos
 
 noinst_PROGRAMS = init loadall simplefake states caps queue registry \
 paranoia rip mp3encode autoplug props case4 markup load tee autoplug2 autoplug3 \
-capsconnect padfactory autoplug4
+capsconnect padfactory autoplug4 incsched reaping threadlock mp1vid
 
 # we have nothing but apps here, we can do this safely
 LIBS += $(GST_LIBS)
diff --git a/tests/incsched.c b/tests/incsched.c
new file mode 100644 (file)
index 0000000..f73b617
--- /dev/null
@@ -0,0 +1,135 @@
+#include <stdlib.h>
+#include <gst/gst.h>
+
+int main(int argc,char *argv[]) {
+  GstBin *thread, *bin;
+  GstElement *src, *identity, *sink, *identity2;
+
+  gst_init(&argc,&argv);
+  gst_info_set_categories(-1);
+  gst_debug_set_categories(-1);
+
+  g_print("\n\nConstructing stuff:\n");
+  thread = gst_pipeline_new("thread");
+  bin = gst_bin_new("bin");
+  src = gst_elementfactory_make("fakesrc","src");
+  identity = gst_elementfactory_make("identity","identity");
+  sink = gst_elementfactory_make("fakesink","sink");
+  identity2 = gst_elementfactory_make("identity","identity2");
+
+  g_print("\nAdding src to thread:\n");
+  gst_bin_add(thread,src);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nAdding identity to thread:\n");
+  gst_bin_add(thread,identity);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nRemoving identity from thread:\n");
+  gst_bin_remove(thread, identity);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nAdding identity to thread:\n");
+  gst_bin_add(thread,identity);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nConnecting src to identity:\n");
+  gst_element_connect(src,"src",identity,"sink");
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nDisconnecting src from identity:\n");
+  gst_element_disconnect(src,"src",identity,"sink");
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nConnecting src to identity:\n");
+  gst_element_connect(src,"src",identity,"sink");
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nAdding sink to bin:\n");
+  gst_bin_add(bin,sink);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nAdding bin to thread:\n");
+  gst_bin_add(thread, GST_ELEMENT(bin));
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nConnecting identity to sink:\n");
+  gst_element_connect(identity,"src",sink,"sink");
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nDisconnecting sink:\n");
+  gst_element_disconnect(identity,"src",sink,"sink");
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nAdding identity2 to bin:\n");
+  gst_bin_add(bin, identity2);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nConnecting identity2 to sink\n");
+  gst_element_connect(identity2,"src",sink,"sink");
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nConnecting identity to identity2\n");
+  gst_element_connect(identity,"src",identity2,"sink");
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\n\nNow setting state from NULL to READY:\n");
+  gst_element_set_state(GST_ELEMENT(thread),GST_STATE_READY);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\n\nNow setting state from READY to PLAYING:\n");
+  gst_element_set_state(GST_ELEMENT(thread),GST_STATE_PLAYING);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\n\nIterating:\n");
+  gst_bin_iterate(thread);
+
+  g_print("\n\nNow setting state from PLAYING to READY:\n");
+  gst_element_set_state(GST_ELEMENT(thread),GST_STATE_READY);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\n\nNow setting state from READY to PLAYING:\n");
+  gst_element_set_state(GST_ELEMENT(thread),GST_STATE_PLAYING);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\n\nIterating:\n");
+  gst_bin_iterate(thread);
+
+  g_print("\n\nNow setting state from PLAYING to READY:\n");
+  gst_element_set_state(GST_ELEMENT(thread),GST_STATE_READY);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nDisconnecting identity from identity2:\n");
+  gst_element_disconnect(identity,"src",identity2,"sink");
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nDisconnecting identity2 from sink:\n");
+  gst_element_disconnect(identity2,"src",sink,"sink");
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\nConnecting identity to sink:\n");
+  gst_element_connect(identity,"src",sink,"sink");
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\n\nNow setting identity2 to NULL:\n");
+  gst_element_set_state(identity2,GST_STATE_NULL);
+
+  g_print("\nRemoving identity2 from bin:\n");
+  gst_bin_remove(bin, identity2);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\n\nNow setting state from READY to PLAYING:\n");
+  gst_element_set_state(GST_ELEMENT(thread),GST_STATE_PLAYING);
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  g_print("\n\nIterating:\n");
+  gst_bin_iterate(thread);
+
+//return;
+  g_print("\n\nSetting EOS on fakesrc and iterating again:\n");
+  gtk_object_set(GTK_OBJECT(src),"eos",TRUE,NULL);
+  gst_bin_iterate(thread);
+
+  g_print("\n\nIterating:\n");
+  gst_bin_iterate(thread);
+}
diff --git a/tests/mp1vid.c b/tests/mp1vid.c
new file mode 100644 (file)
index 0000000..2ad61b4
--- /dev/null
@@ -0,0 +1,78 @@
+#include <gst/gst.h>
+
+GstElement *audiothread;
+GstElement *audioqueue;
+GstElement *audiodecode;
+GstElement *audiosink;
+
+void new_pad(GstElement *parse,GstPad *pad,GstElement *pipeline) {
+
+  if (!strncmp(gst_pad_get_name(pad), "audio_", 6)) {
+    fprintf(stderr,"have audio pad\n");
+
+    fprintf(stderr,"creating thread\n");
+    audiothread = gst_elementfactory_make("thread","audiothread");
+    gst_bin_add(GST_BIN(pipeline),audiothread);
+
+    fprintf(stderr,"creating queue\n");
+    audioqueue = gst_elementfactory_make("queue","audioqueue");
+    gst_bin_add(GST_BIN(audiothread),audioqueue);
+    gst_pad_connect(pad,gst_element_get_pad(audioqueue,"sink"));
+
+    fprintf(stderr,"creating decoder\n");
+    audiodecode = gst_elementfactory_make("mad","audiodecode");
+    gst_bin_add(GST_BIN(audiothread),audiodecode);
+    gst_element_connect(audioqueue,"src",audiodecode,"sink");
+
+    fprintf(stderr,"creating esdsink\n");
+    audiosink = gst_elementfactory_make("osssink","audiosink");
+    gst_bin_add(GST_BIN(audiothread),audiosink);
+    gst_element_connect(audiodecode,"src",audiosink,"sink");
+
+    fprintf(stderr,"setting state to PLAYING\n");
+    gst_element_set_state(audiothread,GST_STATE_PLAYING);
+
+    fprintf(stderr,"done dealing with new audio pad\n");
+  }
+}
+
+int main(int argc,char *argv[]) {
+  GstElement *pipeline, *sourcethread, *src, *parse;
+  int i;
+
+  gst_init(&argc,&argv);
+
+  pipeline = gst_pipeline_new("pipeline");
+  sourcethread = gst_elementfactory_make("thread","sourcethread");
+  src = gst_elementfactory_make("disksrc","src");
+  gtk_object_set(GTK_OBJECT(src),"location","/home/omega/media/AlienSong.mpg",NULL);
+  parse = gst_elementfactory_make("mpeg1parse","parse");
+
+  gtk_signal_connect(GTK_OBJECT(parse),"new_pad",
+                      GTK_SIGNAL_FUNC(new_pad),pipeline);
+
+  gst_bin_add(GST_BIN(sourcethread),src);
+  gst_bin_add(GST_BIN(sourcethread),parse);
+
+  gst_element_connect(src,"src",parse,"sink");
+
+  gst_bin_add(GST_BIN(pipeline),sourcethread);
+
+  gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
+
+  gst_element_set_state(pipeline,GST_STATE_PLAYING);
+  sleep(1);
+
+  while (1) {
+//    sleep(1);
+fprintf(stderr,"setting to PAUSED\n");
+    gst_element_set_state(pipeline,GST_STATE_PAUSED);fprintf(stderr,"paused... ");
+//    sleep(1);
+fprintf(stderr,"setting to PLAYING\n");
+    gst_element_set_state(pipeline,GST_STATE_PLAYING);fprintf(stderr,"playing.\n");
+  }
+
+//  for (i=0;i<10;i++)
+//  while (1)
+//    gst_bin_iterate(GST_BIN(pipeline));
+}
index c251eab..a970883 100644 (file)
@@ -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
index e9135fb..70ac4b7 100644 (file)
@@ -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);
 }
index 205d073..4461d47 100644 (file)
@@ -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>
 #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), GST_STATE_PLAYING);
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
   
   // push a buffer... the have_type signal handler will set the found flag
-  gst_bin_iterate (bin);
+  gst_bin_iterate (GST_BIN (pipeline));
   
-  gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
+  gst_element_set_state (pipeline, 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_bin_remove (GST_BIN (pipeline), GST_ELEMENT (bin));
   gst_object_unref (GST_OBJECT (typefind));
+  gst_object_unref (GST_OBJECT (pipeline));
                    
   return caps;
 }
 
 int main(int argc,char *argv[]) 
 {
-  int i;
+  int i, j;
   int num_channels;
+  gboolean done;
   
   char buffer[20];
   
@@ -108,38 +108,41 @@ int main(int argc,char *argv[])
   /* set up output channel and main bin */
   
   /* create adder */
-  adder = gst_elementfactory_make("adder", "adderel");
+  adder = gst_elementfactory_make ("adder", "adderel");
 
   /* create an audio sink */
-  audiosink = gst_elementfactory_make("esdsink", "play_audio");
+  audiosink = gst_elementfactory_make ("esdsink", "play_audio");
 
   /* create main bin */
-  main_bin = gst_bin_new("bin");
+  main_bin = gst_pipeline_new("bin");
 
   /* connect adder and output to bin */
-
-  gst_bin_add(GST_BIN(main_bin), adder);
-  gst_bin_add(GST_BIN(main_bin), audiosink);
+  GST_INFO (0, "main: adding adder to bin");
+  gst_bin_add (GST_BIN(main_bin), adder);
+  GST_INFO (0, "main: adding audiosink to bin");
+  gst_bin_add (GST_BIN(main_bin), audiosink);
 
   /* connect adder and audiosink */
 
   gst_pad_connect(gst_element_get_pad(adder,"src"),
                   gst_element_get_pad(audiosink,"sink"));
   
-  /* create input channels, add to bin and connect */
-
+  /* start looping */
   input_channels = NULL;
   
   for (i = 1; i < argc; ++i)
   {
     printf ("Opening channel %d from file %s...\n", i, argv[i]);
     channel_in = create_input_channel (i, argv[i]);
-    input_channels = g_list_append (input_channels, channel_in);  
-    gst_bin_add(GST_BIN(main_bin), channel_in->pipe);
+    input_channels = g_list_append (input_channels, channel_in);
+
+    if (i > 1) gst_element_set_state (main_bin, GST_STATE_PAUSED);
+    gst_bin_add (GST_BIN(main_bin), channel_in->pipe);
 
     /* request pads and connect to adder */
+    GST_INFO (0, "requesting pad\n");
     pad = gst_element_request_pad_by_name (adder, "sink%d");
-    g_print ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
+    printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
     sprintf (buffer, "channel%d", i);
     gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad);
 
@@ -178,24 +181,32 @@ int main(int argc,char *argv[])
       env_register_cp (channel_in->volenv,  num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */
     }   
     env_register_cp (channel_in->volenv,  num_channels * 10.0      , 1.0 / num_channels); /* to end level */
-  }
-
-  /* sleep a few seconds doesn't seem to help anyway */
 
-  printf ("Sleeping a few seconds ...\n");
-  sleep (2);
-  printf ("Waking up ...\n");
+    xmlSaveFile("mixer.xml", gst_xml_write(GST_ELEMENT(main_bin)));
 
-  
-  /* start playing */
-  gst_element_set_state(main_bin, GST_STATE_PLAYING);
+    /* start playing */
+    gst_element_set_state(main_bin, GST_STATE_PLAYING);
 
-  playing = TRUE;
+    // write out the schedule
+    gst_schedule_show(GST_ELEMENT_SCHED(main_bin));
+    playing = TRUE;
 
-  while (playing) {
+    j = 0;
+    //printf ("main: start iterating from 0");
+    while (playing && j < 100) 
+    {
+//      printf ("main: iterating %d\n", j);
+      gst_bin_iterate(GST_BIN(main_bin));
+     //fprintf(stderr,"after iterate()\n");
+      ++j;
+    }
+  }
+  printf ("main: all the channels are open\n");
+  while (playing) 
+  {
     gst_bin_iterate(GST_BIN(main_bin));
+    //fprintf(stderr,"after iterate()\n");
   }
-
   /* stop the bin */
   gst_element_set_state(main_bin, GST_STATE_NULL);
 
@@ -228,11 +239,10 @@ create_input_channel (int id, char* location)
   GstAutoplug *autoplug;
   GstCaps *srccaps;
   GstElement *new_element;  
+  GstElement *decoder;
 
-#ifdef DEBUG
-  printf ("DEBUG : c_i_p : creating channel with id %d for file %s\n",
+  GST_DEBUG (0, "c_i_p : creating channel with id %d for file %s\n",
                  id, location);
-#endif
   
   /* allocate channel */
 
@@ -245,23 +255,21 @@ create_input_channel (int id, char* location)
 
   /* create channel */
 
-#ifdef DEBUG
-  printf ("DEBUG : c_i_p : creating pipeline\n");
-#endif
+  GST_DEBUG (0, "c_i_p : creating pipeline\n");
 
-  channel->pipe = gst_bin_new ("pipeline");
+  sprintf (buffer, "pipeline%d", id);
+  channel->pipe = gst_bin_new (buffer);
   g_assert(channel->pipe != NULL);    
     
   /* create elements */
 
-#ifdef DEBUG
-  printf ("DEBUG : c_i_p : creating disksrc\n");
-#endif
+  GST_DEBUG(0, "c_i_p : creating disksrc\n");
 
   sprintf (buffer, "disksrc%d", id);
   channel->disksrc = gst_elementfactory_make ("disksrc", buffer);
   g_assert(channel->disksrc != NULL);    
-  
+
+  GST_DEBUG(0, "c_i_p : setting location\n");
   gtk_object_set(GTK_OBJECT(channel->disksrc),"location", location, NULL);
 
   /* add disksrc to the bin before autoplug */
@@ -286,8 +294,24 @@ create_input_channel (int id, char* location)
   printf ("DEBUG : c_i_p : getting srccaps\n");
 #endif
 
+#ifdef WITH_BUG
   srccaps = gst_play_typefind (GST_BIN (channel->pipe), channel->disksrc);
+#endif
+#ifdef WITH_BUG2
+  {
+    GstElement *pipeline;
 
+    pipeline = gst_pipeline_new ("autoplug_pipeline");
+
+    gst_bin_add (GST_BIN (pipeline), channel->pipe);
+    gst_element_set_state (pipeline, GST_STATE_PLAYING);
+    gst_element_set_state (pipeline, GST_STATE_NULL);
+    gst_bin_remove (GST_BIN (pipeline), channel->pipe);
+    
+  }
+#endif
+
+#ifdef AUTOPLUG
   if (!srccaps) {
     g_print ("could not autoplug, unknown media type...\n");
     exit (-1);
@@ -311,7 +335,24 @@ create_input_channel (int id, char* location)
     g_print ("could not autoplug, no suitable codecs found...\n");
     exit (-1);
   }
+
+#else
+
+  new_element = gst_bin_new ("autoplug_bin");
+
+  /* static plug, use mad plugin and assume mp3 input */
+  decoder =  gst_elementfactory_make ("mad", "mpg123");
+
+  gst_bin_add (GST_BIN (new_element), decoder);
+
+  gst_element_add_ghost_pad (new_element, 
+                 gst_element_get_pad (decoder, "sink"), "sink");
+  gst_element_add_ghost_pad (new_element, 
+                 gst_element_get_pad (decoder, "src"), "src_00");
   
+#endif  
+  xmlSaveFile ("mixer.gst", gst_xml_write (new_element));
+
   gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
   gst_bin_add (GST_BIN (channel->pipe), new_element);
   
diff --git a/tests/old/testsuite/refcounting/Makefile.am b/tests/old/testsuite/refcounting/Makefile.am
new file mode 100644 (file)
index 0000000..51df4da
--- /dev/null
@@ -0,0 +1,18 @@
+SUBDIRS =
+
+testprogs = object element pad element_pad bin thread
+
+object_SOURCES = object.c mem.c
+element_SOURCES = element.c mem.c
+pad_SOURCES = pad.c mem.c
+element_pad_SOURCES = element_pad.c mem.c
+bin_SOURCES = bin.c mem.c
+thread_SOURCES = thread.c mem.c
+
+TESTS = $(testprogs)
+
+check_PROGRAMS = $(testprogs)
+
+# we have nothing but apps here, we can do this safely
+LIBS += $(GST_LIBS)
+CFLAGS += $(GST_CFLAGS)
diff --git a/tests/old/testsuite/refcounting/bin.c b/tests/old/testsuite/refcounting/bin.c
new file mode 100644 (file)
index 0000000..16c7eb1
--- /dev/null
@@ -0,0 +1,272 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_bin (void)
+{
+  GstElement *bin;
+  GstElement *element;
+
+  bin = gst_bin_new ("testbin");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  gst_bin_add (GST_BIN (bin), element);
+  element = gst_element_new ();
+  gst_element_set_name (element, "test2");
+  gst_bin_add (GST_BIN (bin), element);
+
+  return bin;
+}
+
+static GstElement*
+create_bin_ghostpads (void)
+{
+  GstElement *bin;
+  GstElement *element1, *element2;
+
+  bin = gst_bin_new ("testbin");
+  element1 = gst_element_new ();
+  gst_element_set_name (element1, "test1");
+  gst_element_add_pad (element1, gst_pad_new ("src1", GST_PAD_SRC));
+  gst_bin_add (GST_BIN (bin), element1);
+  element2 = gst_element_new ();
+  gst_element_set_name (element2, "test2");
+  gst_element_add_pad (element2, gst_pad_new ("sink1", GST_PAD_SINK));
+  gst_bin_add (GST_BIN (bin), element2);
+  gst_element_connect (element1, "src1", element2, "sink1");
+  gst_element_add_ghost_pad (bin, gst_element_get_pad (element2, "sink1"), "ghost_sink");
+
+  return bin;
+}
+
+static void
+add_remove_test1 (void)
+{
+  GstElement *bin;
+  GstElement *element;
+
+  bin = gst_bin_new ("testbin");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (bin), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  gst_bin_remove (GST_BIN (bin), element);
+
+  gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test2 (void)
+{
+  GstElement *bin;
+  GstElement *element;
+
+  bin = gst_bin_new ("testbin");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  gst_object_ref (GST_OBJECT (element));
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (bin), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  gst_bin_remove (GST_BIN (bin), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  g_assert (!GST_OBJECT_DESTROYED (element));
+
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (GST_OBJECT_DESTROYED (element));
+  gst_object_unref (GST_OBJECT (element));
+
+  gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test3 (void)
+{
+  GstElement *bin;
+  GstElement *element;
+
+  bin = gst_bin_new ("testbin");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (bin), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
+
+  gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test4 (void)
+{
+  GstElement *bin, *bin2;
+  GstElement *element;
+
+  bin = gst_bin_new ("testbin");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (bin), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+
+  bin2 = create_bin ();
+  g_assert (GST_OBJECT_FLOATING (bin2));
+  gst_bin_add (GST_BIN (bin), bin2);
+  g_assert (!GST_OBJECT_FLOATING (bin2));
+
+  gst_object_destroy (GST_OBJECT (bin2));
+  g_assert (gst_bin_get_by_name (GST_BIN (bin), "testbin") == NULL);
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
+
+  gst_object_unref (GST_OBJECT (bin));
+}
+
+int
+main (int argc, gchar *argv[])
+{
+  GstElement *bin;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+  g_print ("starting test\n");
+  usage1 = vmsize();
+
+  bin = gst_bin_new ("somebin");
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("create/unref new bin %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+  bin = gst_bin_new ("somebin");
+  g_assert (GST_OBJECT_FLOATING (bin));
+  gst_object_ref (GST_OBJECT (bin));
+  gst_object_sink (GST_OBJECT (bin));
+  g_assert (!GST_OBJECT_FLOATING (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("create/ref/sink/unref new bin %ld\n", vmsize()-usage1);
+
+
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_ref (GST_OBJECT (bin));
+    gst_object_sink (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/ref/sink/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+  bin = gst_bin_new ("somebin");
+  g_assert (!GST_OBJECT_DESTROYED (bin));
+  gst_object_destroy (GST_OBJECT (bin));
+  g_assert (GST_OBJECT_DESTROYED (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("create/destroy/unref new bin %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_destroy (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/destroy/unref %d bin %ld\n", iters, vmsize()-usage1);
+
+  bin = gst_bin_new ("somebin");
+  gst_object_ref (GST_OBJECT (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("create/ref/unref/unref new bin %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_ref (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/ref/unref/unref %d bin %ld\n", iters, vmsize()-usage1);
+
+  bin = gst_bin_new ("somebin");
+  gst_object_ref (GST_OBJECT (bin));
+  gst_object_destroy (GST_OBJECT (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("craete/ref/destroy/unref/unref new bin %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_ref (GST_OBJECT (bin));
+    gst_object_destroy (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_ref (GST_OBJECT (bin));
+    gst_element_set_name (bin, "testing123");
+    gst_object_destroy (GST_OBJECT (bin));
+    gst_element_set_name (bin, "testing123");
+    gst_object_unref (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d bins with name %ld\n", iters, vmsize()-usage1);
+
+  bin = gst_bin_new ("somebin");
+  for (i=0; i<iters;i++) {
+    gst_element_set_name (bin, "testing");
+  }
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    bin = create_bin();
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/unref %d bin with children %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters/2;i++) {
+    bin = create_bin_ghostpads();
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/unref %d bin with children and ghostpads %ld\n", iters/2, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test1();
+  }
+  g_print ("add/remove test1 %d in bin %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test2();
+  }
+  g_print ("add/remove test2 %d in bin %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test3();
+  }
+  g_print ("add/destroy/remove test3 %d in bin %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test4();
+  }
+  g_print ("add/destroy/remove test4 %d in bin %ld\n", iters, vmsize()-usage1);
+
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/tests/old/testsuite/refcounting/element.c b/tests/old/testsuite/refcounting/element.c
new file mode 100644 (file)
index 0000000..f61ffbc
--- /dev/null
@@ -0,0 +1,116 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+  GstElement *element;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+  g_print ("starting test\n");
+  usage1 = vmsize();
+
+  element = gst_element_new ();
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("create/unref new element %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+  element = gst_element_new ();
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_object_ref (GST_OBJECT (element));
+  gst_object_sink (GST_OBJECT (element));
+  g_assert (!GST_OBJECT_FLOATING (element));
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("create/ref/sink/unref new element %ld\n", vmsize()-usage1);
+
+
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_ref (GST_OBJECT (element));
+    gst_object_sink (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/ref/sink/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+  element = gst_element_new ();
+  g_assert (!GST_OBJECT_DESTROYED (element));
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (GST_OBJECT_DESTROYED (element));
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("create/destroy/unref new element %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_destroy (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/destroy/unref %d element %ld\n", iters, vmsize()-usage1);
+
+  element = gst_element_new ();
+  gst_object_ref (GST_OBJECT (element));
+  gst_object_unref (GST_OBJECT (element));
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("create/ref/unref/unref new element %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_ref (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/ref/unref/unref %d element %ld\n", iters, vmsize()-usage1);
+
+  element = gst_element_new ();
+  gst_object_ref (GST_OBJECT (element));
+  gst_object_destroy (GST_OBJECT (element));
+  gst_object_unref (GST_OBJECT (element));
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("craete/ref/destroy/unref/unref new element %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_ref (GST_OBJECT (element));
+    gst_object_destroy (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_ref (GST_OBJECT (element));
+    gst_element_set_name (element, "testing123");
+    gst_object_destroy (GST_OBJECT (element));
+    gst_element_set_name (element, "testing123");
+    gst_object_unref (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d elements with name %ld\n", iters, vmsize()-usage1);
+
+  element = gst_element_new ();
+  for (i=0; i<iters;i++) {
+    gst_element_set_name (element, "testing");
+  }
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/tests/old/testsuite/refcounting/element_pad.c b/tests/old/testsuite/refcounting/element_pad.c
new file mode 100644 (file)
index 0000000..0f80291
--- /dev/null
@@ -0,0 +1,134 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_element (gchar *padname, GstPadDirection dir)
+{
+  GstElement *element;
+  GstPad *pad;
+
+  element = gst_element_new ();
+  pad = gst_pad_new (padname, dir);
+  gst_element_add_pad (element, pad);
+
+  return element;
+}
+
+int
+main (int argc, gchar *argv[])
+{
+  GstElement *element;
+  GstElement *element2;
+  GstPad *pad;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+
+  g_print ("starting element with pad test with %d iterations\n", iters);
+  usage1 = vmsize();
+
+  element = create_element ("sink", GST_PAD_SINK);
+  pad = gst_element_get_pad (element, "sink");
+  g_assert (GST_OBJECT_FLOATING (element));
+  g_assert (!GST_OBJECT_FLOATING (pad));
+  g_assert (gst_pad_get_parent (pad) == element);
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("create/addpad/unref new element %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/addpad/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    element2 = create_element ("src", GST_PAD_SRC);
+    gst_element_connect (element, "sink", element2, "src");
+    g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+    g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element, "sink")));
+    gst_object_unref (GST_OBJECT (element));
+    g_assert (!GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+    gst_object_unref (GST_OBJECT (element2));
+  }
+  g_print ("create/connect/unref %d elements %ld\n", iters/2, vmsize()-usage1);
+
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    element2 = create_element ("src", GST_PAD_SRC);
+    gst_element_connect (element, "sink", element2, "src");
+    g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+    g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element, "sink")));
+    gst_object_destroy (GST_OBJECT (element));
+    g_assert (GST_OBJECT_DESTROYED (element));
+    g_assert (!GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+    gst_object_unref (GST_OBJECT (element2));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/connect/destroy %d elements %ld\n", iters/2, vmsize()-usage1);
+
+  element = create_element ("sink", GST_PAD_SINK);
+  pad = gst_element_get_pad (element, "sink");
+  gst_element_remove_pad (element, pad);
+  g_assert (gst_element_get_pad (element, "sink") == NULL);
+
+  g_print ("pad removal ok %ld\n", vmsize()-usage1);
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    pad = gst_element_get_pad (element, "sink");
+    gst_element_remove_pad (element, pad);
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("pad removal loop %d  %ld\n", iters/2, vmsize()-usage1);
+
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    pad = gst_element_get_pad (element, "sink");
+    gst_object_ref (GST_OBJECT (pad));
+    gst_element_remove_pad (element, pad);
+    g_assert (gst_pad_get_parent (pad) == NULL);
+    gst_object_unref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("pad removal and test loop %d  %ld\n", iters/2, vmsize()-usage1);
+
+  element = create_element ("sink", GST_PAD_SINK);
+  pad = gst_element_get_pad (element, "sink");
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (GST_OBJECT_DESTROYED (element));
+  g_assert (gst_element_get_pad (element, "sink") == NULL);
+  gst_object_unref (GST_OBJECT (element));
+
+  g_print ("pad destroy/removal ok %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    pad = gst_element_get_pad (element, "sink");
+    gst_object_destroy (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("pad destroy/removal loop %d %ld\n", iters/2, vmsize()-usage1);
+
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    pad = gst_element_get_pad (element, "sink");
+    gst_object_destroy (GST_OBJECT (pad));
+    g_assert (gst_element_get_pad (element, "sink") == NULL);
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("pad destroy loop %d %ld\n", iters/2, vmsize()-usage1);
+
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/tests/old/testsuite/refcounting/mem.c b/tests/old/testsuite/refcounting/mem.c
new file mode 100644 (file)
index 0000000..8e1c573
--- /dev/null
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int vmsize() {
+  int pid,fd,size,i,mem;
+  char filename[17], buf[256], *ptr, *end;
+
+  pid = getpid();
+  snprintf(filename,17,"/proc/%d/stat",pid);
+  fd = open(filename,O_RDONLY);
+  size = read(fd,buf,240);
+  ptr = buf;
+  for (i=0;i<22;i++)
+    ptr = (char *)strchr(ptr,' ') + 1;
+  end = (char *)strchr(ptr,' ');
+  *end = 0;
+  sscanf(ptr,"%d",&mem);
+  close(fd);
+  return mem;
+}
diff --git a/tests/old/testsuite/refcounting/mem.h b/tests/old/testsuite/refcounting/mem.h
new file mode 100644 (file)
index 0000000..28999db
--- /dev/null
@@ -0,0 +1 @@
+int vmsize();
diff --git a/tests/old/testsuite/refcounting/object.c b/tests/old/testsuite/refcounting/object.c
new file mode 100644 (file)
index 0000000..477ec9b
--- /dev/null
@@ -0,0 +1,156 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+  GstObject *object, *object2;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+  g_print ("starting test with %d iterations\n", iters);
+  usage1 = vmsize();
+  object = gst_object_new ();
+  gst_object_unref (object);
+  g_print ("create/unref new object %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_unref (object);
+
+  }
+  g_print ("create/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  g_assert (GST_OBJECT_FLOATING (object));
+  gst_object_ref (object);
+  gst_object_sink (object);
+  g_assert (!GST_OBJECT_FLOATING (object));
+  gst_object_unref (object);
+  g_print ("create/ref/sink/unref new object %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_ref (object);
+    gst_object_sink (object);
+    gst_object_unref (object);
+  }
+  g_print ("create/ref/sink/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  g_assert (!GST_OBJECT_DESTROYED (object));
+  gst_object_destroy (object);
+  g_assert (GST_OBJECT_DESTROYED (object));
+  gst_object_unref (object);
+  g_print ("create/destroy/unref new object %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_destroy (object);
+    gst_object_unref (object);
+  }
+  g_print ("destroy/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  gst_object_ref (object);
+  gst_object_unref (object);
+  gst_object_unref (object);
+  g_print ("create/ref/unref/unref new object %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_ref (object);
+    gst_object_unref (object);
+    gst_object_unref (object);
+  }
+  g_print ("create/ref/unref/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  gst_object_ref (object);
+  gst_object_destroy (object);
+  gst_object_unref (object);
+  gst_object_unref (object);
+  g_print ("create/ref/destroy/unref/unref new object %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_ref (object);
+    gst_object_destroy (object);
+    gst_object_unref (object);
+    gst_object_unref (object);
+  }
+  g_print ("create/ref/destroy/unref/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_ref (object);
+    gst_object_set_name (object, "testing123");
+    gst_object_destroy (object);
+    gst_object_set_name (object, "testing123");
+    gst_object_unref (object);
+    gst_object_unref (object);
+  }
+  g_print ("create/ref/destroy/unref/unref %d object  with name %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  for (i=0; i<iters;i++) {
+    gst_object_set_name (object, "testing");
+  }
+  gst_object_unref (object);
+  g_print ("create/set name/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  object2 = gst_object_new ();
+  g_assert (GST_OBJECT_FLOATING (object));
+  g_assert (GST_OBJECT_FLOATING (object2));
+
+  gst_object_set_parent (object, object2);
+  g_assert (GST_OBJECT_FLOATING (object2));
+  g_assert (!GST_OBJECT_FLOATING (object));
+
+  g_print ("parentage flags set_parent ok %ld\n", vmsize()-usage1);
+
+  gst_object_ref (object);
+  gst_object_unparent (object);
+  g_assert (GST_OBJECT_FLOATING (object2));
+  g_assert (!GST_OBJECT_FLOATING (object));
+  g_assert (gst_object_get_parent (object) == NULL);
+
+  g_print ("parentage flags unparent ok %ld\n", vmsize()-usage1);
+
+  gst_object_set_parent (object, object2);
+  g_assert (GST_OBJECT_FLOATING (object2));
+  g_assert (!GST_OBJECT_FLOATING (object));
+  g_assert (gst_object_get_parent (object) == object2);
+
+  gst_object_destroy (object);
+  g_assert (GST_OBJECT_DESTROYED (object));
+  g_assert (!GST_OBJECT_FLOATING (object));
+  g_assert (gst_object_get_parent (object) == NULL);
+  gst_object_unref (object);
+
+  g_print ("parentage flags destroy ok %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    object2 = gst_object_new ();
+    gst_object_set_parent (object2, object);
+    gst_object_unref (object);
+    gst_object_unref (object2);
+  }
+  g_print ("create/unref %d 2 parented objects %ld\n", iters, vmsize()-usage1);
+
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/tests/old/testsuite/refcounting/pad.c b/tests/old/testsuite/refcounting/pad.c
new file mode 100644 (file)
index 0000000..fed2554
--- /dev/null
@@ -0,0 +1,223 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+  GstPad *pad;
+  GstPad *pad2;
+  GstPadTemplate *padtempl;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+  g_print ("starting pad test\n");
+  usage1 = vmsize();
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("create/unref new pad %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  g_assert (GST_OBJECT_FLOATING (pad));
+  gst_object_ref (GST_OBJECT (pad));
+  gst_object_sink (GST_OBJECT (pad));
+  g_assert (!GST_OBJECT_FLOATING (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("create/ref/sink/unref new pad %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_ref (GST_OBJECT (pad));
+    gst_object_sink (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/ref/sink/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  g_assert (!GST_OBJECT_DESTROYED (pad));
+  gst_object_destroy (GST_OBJECT (pad));
+  g_assert (GST_OBJECT_DESTROYED (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("create/destroy/unref pad %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_destroy (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/destroy/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  gst_object_ref (GST_OBJECT (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("create/ref/unref/unref pad %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_ref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/ref/unref/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  gst_object_ref (GST_OBJECT (pad));
+  gst_object_destroy (GST_OBJECT (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("create/ref/destroy/unref/unref pad %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_ref (GST_OBJECT (pad));
+    gst_object_destroy (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/ref/destroy/unref/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_ref (GST_OBJECT (pad));
+    gst_pad_set_name (pad, "testing123");
+    gst_object_destroy (GST_OBJECT (pad));
+    gst_pad_set_name (pad, "testing123");
+    gst_object_unref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/ref/destroy/unref/unref %d pads %ld with name\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  for (i=0; i<iters;i++) {
+    gst_pad_set_name (pad, "testing");
+  }
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+  gst_pad_connect (pad2, pad);
+  g_assert (GST_PAD_CONNECTED (pad));
+  g_assert (GST_PAD_CONNECTED (pad2));
+  gst_pad_disconnect (pad2, pad);
+  g_assert (!GST_PAD_CONNECTED (pad));
+  g_assert (!GST_PAD_CONNECTED (pad2));
+  g_print ("connect/disconnect pad %ld\n", vmsize()-usage1);
+  gst_pad_connect (pad, pad2);
+  g_assert (GST_PAD_CONNECTED (pad));
+  g_assert (GST_PAD_CONNECTED (pad2));
+  gst_pad_disconnect (pad, pad2);
+  g_assert (!GST_PAD_CONNECTED (pad));
+  g_assert (!GST_PAD_CONNECTED (pad2));
+  g_print ("connect/disconnect pad wrong direction %ld\n", vmsize()-usage1);
+
+  gst_object_unref (GST_OBJECT (pad));
+  gst_object_unref (GST_OBJECT (pad2));
+
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+    gst_pad_connect (pad2, pad);
+    gst_pad_disconnect (pad2, pad);
+    gst_pad_connect (pad, pad2);
+    gst_pad_disconnect (pad, pad2);
+    gst_object_unref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad2));
+  }
+  g_print ("connect/disconnect %d pads %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+  gst_pad_connect (pad2, pad);
+  g_assert (GST_PAD_CONNECTED (pad2));
+  g_assert (GST_PAD_CONNECTED (pad));
+
+  gst_object_unref (GST_OBJECT (pad2));
+  g_assert (!GST_PAD_CONNECTED (pad));
+  g_assert (!GST_OBJECT_DESTROYED (pad));
+  gst_object_unref (GST_OBJECT (pad));
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+  gst_pad_connect (pad2, pad);
+  g_assert (GST_PAD_CONNECTED (pad2));
+  g_assert (GST_PAD_CONNECTED (pad));
+
+  gst_object_unref (GST_OBJECT (pad));
+  g_assert (!GST_PAD_CONNECTED (pad2));
+  g_assert (!GST_OBJECT_DESTROYED (pad2));
+  gst_object_unref (GST_OBJECT (pad2));
+
+  g_print ("pad unref effects on connect pad ok %ld\n", vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+  gst_pad_connect (pad2, pad);
+  g_assert (GST_PAD_CONNECTED (pad2));
+  g_assert (GST_PAD_CONNECTED (pad));
+
+  gst_object_destroy (GST_OBJECT (pad2));
+  g_assert (GST_OBJECT_DESTROYED (pad2));
+  g_assert (!GST_OBJECT_DESTROYED (pad));
+  g_assert (!GST_PAD_CONNECTED (pad));
+  gst_object_unref (GST_OBJECT (pad2));
+  g_assert (!GST_OBJECT_DESTROYED (pad));
+  g_assert (!GST_PAD_CONNECTED (pad));
+  gst_object_unref (GST_OBJECT (pad));
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+  gst_pad_connect (pad2, pad);
+  g_assert (GST_PAD_CONNECTED (pad2));
+  g_assert (GST_PAD_CONNECTED (pad));
+
+  gst_object_destroy (GST_OBJECT (pad));
+  g_assert (GST_OBJECT_DESTROYED (pad));
+  g_assert (!GST_OBJECT_DESTROYED (pad2));
+  g_assert (!GST_PAD_CONNECTED (pad2));
+  gst_object_unref (GST_OBJECT (pad));
+  g_assert (!GST_OBJECT_DESTROYED (pad2));
+  g_assert (!GST_PAD_CONNECTED (pad2));
+  gst_object_unref (GST_OBJECT (pad2));
+
+  g_print ("pad destroy effects on connect pad ok %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    padtempl = gst_padtemplate_new ("sink%d", GST_PAD_SINK, GST_PAD_SOMETIMES, NULL);
+    gst_object_unref (GST_OBJECT (padtempl));
+  }
+  g_print ("%d padtemplates create/unref %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    padtempl = gst_padtemplate_new ("sink%d", GST_PAD_SINK, GST_PAD_SOMETIMES, NULL);
+    pad = gst_pad_new_from_template (padtempl, "sink1");
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("%d pads create/unref from padtemplate %ld\n", iters, vmsize()-usage1);
+  
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return vmsize()-usage1;
+}
diff --git a/tests/old/testsuite/refcounting/thread.c b/tests/old/testsuite/refcounting/thread.c
new file mode 100644 (file)
index 0000000..f229a54
--- /dev/null
@@ -0,0 +1,281 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_thread (void)
+{
+  GstElement *thread;
+  GstElement *element;
+
+  thread = gst_thread_new ("testthread");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  gst_bin_add (GST_BIN (thread), element);
+  element = gst_element_new ();
+  gst_element_set_name (element, "test2");
+  gst_bin_add (GST_BIN (thread), element);
+
+  return thread;
+}
+
+static GstElement*
+create_thread_ghostpads (void)
+{
+  GstElement *thread;
+  GstElement *element1, *element2;
+
+  thread = gst_thread_new ("testthread");
+  element1 = gst_element_new ();
+  gst_element_set_name (element1, "test1");
+  gst_element_add_pad (element1, gst_pad_new ("src1", GST_PAD_SRC));
+  gst_bin_add (GST_BIN (thread), element1);
+  element2 = gst_element_new ();
+  gst_element_set_name (element2, "test2");
+  gst_element_add_pad (element2, gst_pad_new ("sink1", GST_PAD_SINK));
+  gst_bin_add (GST_BIN (thread), element2);
+  gst_element_connect (element1, "src1", element2, "sink1");
+  gst_element_add_ghost_pad (thread, gst_element_get_pad (element2, "sink1"), "sink1");
+
+  return thread;
+}
+
+static void
+add_remove_test1 (void)
+{
+  GstElement *thread;
+  GstElement *element;
+
+  thread = gst_thread_new ("testthread");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (thread), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  gst_bin_remove (GST_BIN (thread), element);
+
+  gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test2 (void)
+{
+  GstElement *thread;
+  GstElement *element;
+
+  thread = gst_thread_new ("testthread");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  gst_object_ref (GST_OBJECT (element));
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (thread), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  gst_bin_remove (GST_BIN (thread), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  g_assert (!GST_OBJECT_DESTROYED (element));
+
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (GST_OBJECT_DESTROYED (element));
+  gst_object_unref (GST_OBJECT (element));
+
+  gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test3 (void)
+{
+  GstElement *thread;
+  GstElement *element;
+
+  thread = gst_thread_new ("testthread");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (thread), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (gst_bin_get_by_name (GST_BIN (thread), "test1") == NULL);
+
+  gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test4 (void)
+{
+  GstElement *thread, *thread2;
+  GstElement *element;
+
+  thread = gst_thread_new ("testthread");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (thread), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+
+  thread2 = create_thread ();
+  g_assert (GST_OBJECT_FLOATING (thread2));
+  gst_bin_add (GST_BIN (thread), thread2);
+  g_assert (!GST_OBJECT_FLOATING (thread2));
+
+  gst_object_destroy (GST_OBJECT (thread2));
+  g_assert (gst_bin_get_by_name (GST_BIN (thread), "testthread") == NULL);
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (gst_bin_get_by_name (GST_BIN (thread), "test1") == NULL);
+
+  gst_object_unref (GST_OBJECT (thread));
+}
+
+int
+main (int argc, gchar *argv[])
+{
+  GstElement *thread, *element;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+  g_print ("starting test\n");
+  usage1 = vmsize();
+
+  thread = gst_thread_new ("somethread");
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("create/unref new thread %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+  thread = gst_thread_new ("somethread");
+  g_assert (GST_OBJECT_FLOATING (thread));
+  gst_object_ref (GST_OBJECT (thread));
+  gst_object_sink (GST_OBJECT (thread));
+  g_assert (!GST_OBJECT_FLOATING (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("create/ref/sink/unref new thread %ld\n", vmsize()-usage1);
+
+
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_ref (GST_OBJECT (thread));
+    gst_object_sink (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/ref/sink/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+  thread = gst_thread_new ("somethread");
+  g_assert (!GST_OBJECT_DESTROYED (thread));
+  gst_object_destroy (GST_OBJECT (thread));
+  g_assert (GST_OBJECT_DESTROYED (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("create/destroy/unref new thread %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_destroy (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/destroy/unref %d thread %ld\n", iters, vmsize()-usage1);
+
+  thread = gst_thread_new ("somethread");
+  gst_object_ref (GST_OBJECT (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("create/ref/unref/unref new thread %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_ref (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/ref/unref/unref %d thread %ld\n", iters, vmsize()-usage1);
+
+  thread = gst_thread_new ("somethread");
+  gst_object_ref (GST_OBJECT (thread));
+  gst_object_destroy (GST_OBJECT (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("craete/ref/destroy/unref/unref new thread %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_ref (GST_OBJECT (thread));
+    gst_object_destroy (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_ref (GST_OBJECT (thread));
+    gst_element_set_name (thread, "testing123");
+    gst_object_destroy (GST_OBJECT (thread));
+    gst_element_set_name (thread, "testing123");
+    gst_object_unref (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d threads with name %ld\n", iters, vmsize()-usage1);
+
+  thread = gst_thread_new ("somethread");
+  for (i=0; i<iters;i++) {
+    gst_element_set_name (thread, "testing");
+  }
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    element = gst_element_new ();
+    gst_element_set_name (element, "test1");
+    gst_bin_add (GST_BIN (thread), element);
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/unref %d thread with one element %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    thread = create_thread();
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/unref %d thread with children %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters/2;i++) {
+    thread = create_thread_ghostpads();
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/unref %d thread with children and ghostpads %ld\n", iters/2, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test1();
+  }
+  g_print ("add/remove test1 %d in thread %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test2();
+  }
+  g_print ("add/remove test2 %d in thread %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test3();
+  }
+  g_print ("add/destroy/remove test3 %d in thread %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test4();
+  }
+  g_print ("add/destroy/remove test4 %d in thread %ld\n", iters, vmsize()-usage1);
+
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/tests/reaping.c b/tests/reaping.c
new file mode 100644 (file)
index 0000000..3714e54
--- /dev/null
@@ -0,0 +1,35 @@
+#include <stdio.h>
+#include <gst/gst.h>
+
+int main(int argc,char *argv[]) {
+  GstBin *pipeline, *thread;
+  GstElement *src, *queue1, *sink;
+
+  gst_init(&argc,&argv);
+  gst_info_set_categories(-1);
+  gst_debug_set_categories(-1);
+
+  pipeline = gst_pipeline_new("pipeline");
+  thread = gst_thread_new("thread");
+  src = gst_elementfactory_make("fakesrc","src");
+  queue1 = gst_elementfactory_make("queue","queue");
+  sink = gst_elementfactory_make("fakesink","sink");
+
+  gst_bin_add(pipeline,src);
+  gst_bin_add(pipeline,queue1);
+  gst_bin_add(pipeline,GST_ELEMENT(thread));
+  gst_bin_add(thread,sink);
+
+  gst_element_add_ghost_pad(GST_ELEMENT(thread),gst_element_get_pad(sink,"sink"),"sink");
+
+  gst_element_connect (src,"src",queue1,"sink");
+  gst_element_connect (queue1, "src", thread, "sink");
+
+
+  fprintf(stderr,"\n\n\n");
+  gst_element_set_state (pipeline, GST_STATE_READY);
+
+
+  fprintf(stderr,"\n\n\n");
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+}
index 3d5b6ac..26dbc74 100644 (file)
@@ -2,7 +2,7 @@
 
 gboolean state_change(GstElement *element,GstElementState state) {
   g_print(">STATES: element '%s' state set to %d(%s)\n",
-       gst_element_get_name(element),state,_gst_print_statename(state));
+       gst_element_get_name(element),state,gst_element_statename(state));
   g_print(">STATES: element state is actually %d\n",GST_STATE(element));
 
   return TRUE;
@@ -37,15 +37,15 @@ int main(int argc,char *argv[]) {
                      GTK_SIGNAL_FUNC(state_change),NULL);
 
   g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(src),
-       GST_STATE(src),_gst_print_statename(GST_STATE(src)));
+       GST_STATE(src),gst_element_statename(GST_STATE(src)));
   g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(subbin),
-       GST_STATE(subbin),_gst_print_statename(GST_STATE(subbin)));
+       GST_STATE(subbin),gst_element_statename(GST_STATE(subbin)));
   g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(filter),
-       GST_STATE(filter),_gst_print_statename(GST_STATE(filter)));
+       GST_STATE(filter),gst_element_statename(GST_STATE(filter)));
   g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(sink),
-       GST_STATE(sink),_gst_print_statename(GST_STATE(sink)));
+       GST_STATE(sink),gst_element_statename(GST_STATE(sink)));
   g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(bin),
-       GST_STATE(bin),_gst_print_statename(GST_STATE(bin)));
+       GST_STATE(bin),gst_element_statename(GST_STATE(bin)));
 
   gst_bin_add(GST_BIN(subbin),filter);
   gst_element_add_ghost_pad(GST_ELEMENT(bin),gst_element_get_pad(filter,"sink"),"sink");
diff --git a/tests/threadlock.c b/tests/threadlock.c
new file mode 100644 (file)
index 0000000..83b62aa
--- /dev/null
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <gst/gst.h>
+
+int main(int argc,char *argv[]) {
+  GstBin *pipeline, *thread;
+  GstElement *src, *queue1, *sink;
+
+  gst_init(&argc,&argv);
+  gst_info_set_categories(-1);
+  gst_debug_set_categories(-1);
+
+  pipeline = gst_pipeline_new("pipeline");
+  thread = gst_thread_new("thread");
+  src = gst_elementfactory_make("fakesrc","src");
+  sink = gst_elementfactory_make("fakesink","sink");
+
+  fprintf(stderr,"ADDING src\n");
+  gst_bin_add(thread,src);
+  fprintf(stderr,"ADDING sink\n");
+  gst_bin_add(thread,sink);
+  fprintf(stderr,"ADDING thread\n");
+  gst_bin_add(pipeline,GST_ELEMENT(thread));
+
+//  gst_element_add_ghost_pad(GST_ELEMENT(thread),gst_element_get_pad(sink,"sink"),"sink");
+
+  fprintf(stderr,"CONNECTING src to sink\n");
+  gst_element_connect (src, "src", sink, "sink");
+
+  fprintf(stderr,"\nSWITCHING to READY:\n");
+  gst_element_set_state (thread, GST_STATE_READY);
+  fprintf(stderr,"\nPIPELINE sched:\n");
+  gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
+  fprintf(stderr,"\nTHREAD sched:\n");
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+  fprintf(stderr,"\nSWITCHING to PLAYING:\n");
+  gst_element_set_state (thread, GST_STATE_PLAYING);
+  gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+fprintf(stderr,"sleeping...\n");
+sleep(1);
+fprintf(stderr,"done sleeping...\n");
+
+  fprintf(stderr,"\nSWITCHING to READY:\n");
+  gst_element_set_state (thread, GST_STATE_READY);
+  gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
+  gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+sleep(1);
+}
diff --git a/testsuite/refcounting/Makefile.am b/testsuite/refcounting/Makefile.am
new file mode 100644 (file)
index 0000000..51df4da
--- /dev/null
@@ -0,0 +1,18 @@
+SUBDIRS =
+
+testprogs = object element pad element_pad bin thread
+
+object_SOURCES = object.c mem.c
+element_SOURCES = element.c mem.c
+pad_SOURCES = pad.c mem.c
+element_pad_SOURCES = element_pad.c mem.c
+bin_SOURCES = bin.c mem.c
+thread_SOURCES = thread.c mem.c
+
+TESTS = $(testprogs)
+
+check_PROGRAMS = $(testprogs)
+
+# we have nothing but apps here, we can do this safely
+LIBS += $(GST_LIBS)
+CFLAGS += $(GST_CFLAGS)
diff --git a/testsuite/refcounting/bin.c b/testsuite/refcounting/bin.c
new file mode 100644 (file)
index 0000000..16c7eb1
--- /dev/null
@@ -0,0 +1,272 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_bin (void)
+{
+  GstElement *bin;
+  GstElement *element;
+
+  bin = gst_bin_new ("testbin");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  gst_bin_add (GST_BIN (bin), element);
+  element = gst_element_new ();
+  gst_element_set_name (element, "test2");
+  gst_bin_add (GST_BIN (bin), element);
+
+  return bin;
+}
+
+static GstElement*
+create_bin_ghostpads (void)
+{
+  GstElement *bin;
+  GstElement *element1, *element2;
+
+  bin = gst_bin_new ("testbin");
+  element1 = gst_element_new ();
+  gst_element_set_name (element1, "test1");
+  gst_element_add_pad (element1, gst_pad_new ("src1", GST_PAD_SRC));
+  gst_bin_add (GST_BIN (bin), element1);
+  element2 = gst_element_new ();
+  gst_element_set_name (element2, "test2");
+  gst_element_add_pad (element2, gst_pad_new ("sink1", GST_PAD_SINK));
+  gst_bin_add (GST_BIN (bin), element2);
+  gst_element_connect (element1, "src1", element2, "sink1");
+  gst_element_add_ghost_pad (bin, gst_element_get_pad (element2, "sink1"), "ghost_sink");
+
+  return bin;
+}
+
+static void
+add_remove_test1 (void)
+{
+  GstElement *bin;
+  GstElement *element;
+
+  bin = gst_bin_new ("testbin");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (bin), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  gst_bin_remove (GST_BIN (bin), element);
+
+  gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test2 (void)
+{
+  GstElement *bin;
+  GstElement *element;
+
+  bin = gst_bin_new ("testbin");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  gst_object_ref (GST_OBJECT (element));
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (bin), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  gst_bin_remove (GST_BIN (bin), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  g_assert (!GST_OBJECT_DESTROYED (element));
+
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (GST_OBJECT_DESTROYED (element));
+  gst_object_unref (GST_OBJECT (element));
+
+  gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test3 (void)
+{
+  GstElement *bin;
+  GstElement *element;
+
+  bin = gst_bin_new ("testbin");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (bin), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
+
+  gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test4 (void)
+{
+  GstElement *bin, *bin2;
+  GstElement *element;
+
+  bin = gst_bin_new ("testbin");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (bin), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+
+  bin2 = create_bin ();
+  g_assert (GST_OBJECT_FLOATING (bin2));
+  gst_bin_add (GST_BIN (bin), bin2);
+  g_assert (!GST_OBJECT_FLOATING (bin2));
+
+  gst_object_destroy (GST_OBJECT (bin2));
+  g_assert (gst_bin_get_by_name (GST_BIN (bin), "testbin") == NULL);
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
+
+  gst_object_unref (GST_OBJECT (bin));
+}
+
+int
+main (int argc, gchar *argv[])
+{
+  GstElement *bin;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+  g_print ("starting test\n");
+  usage1 = vmsize();
+
+  bin = gst_bin_new ("somebin");
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("create/unref new bin %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+  bin = gst_bin_new ("somebin");
+  g_assert (GST_OBJECT_FLOATING (bin));
+  gst_object_ref (GST_OBJECT (bin));
+  gst_object_sink (GST_OBJECT (bin));
+  g_assert (!GST_OBJECT_FLOATING (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("create/ref/sink/unref new bin %ld\n", vmsize()-usage1);
+
+
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_ref (GST_OBJECT (bin));
+    gst_object_sink (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/ref/sink/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+  bin = gst_bin_new ("somebin");
+  g_assert (!GST_OBJECT_DESTROYED (bin));
+  gst_object_destroy (GST_OBJECT (bin));
+  g_assert (GST_OBJECT_DESTROYED (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("create/destroy/unref new bin %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_destroy (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/destroy/unref %d bin %ld\n", iters, vmsize()-usage1);
+
+  bin = gst_bin_new ("somebin");
+  gst_object_ref (GST_OBJECT (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("create/ref/unref/unref new bin %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_ref (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/ref/unref/unref %d bin %ld\n", iters, vmsize()-usage1);
+
+  bin = gst_bin_new ("somebin");
+  gst_object_ref (GST_OBJECT (bin));
+  gst_object_destroy (GST_OBJECT (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("craete/ref/destroy/unref/unref new bin %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_ref (GST_OBJECT (bin));
+    gst_object_destroy (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    bin = gst_bin_new ("somebin");
+    gst_object_ref (GST_OBJECT (bin));
+    gst_element_set_name (bin, "testing123");
+    gst_object_destroy (GST_OBJECT (bin));
+    gst_element_set_name (bin, "testing123");
+    gst_object_unref (GST_OBJECT (bin));
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d bins with name %ld\n", iters, vmsize()-usage1);
+
+  bin = gst_bin_new ("somebin");
+  for (i=0; i<iters;i++) {
+    gst_element_set_name (bin, "testing");
+  }
+  gst_object_unref (GST_OBJECT (bin));
+  g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    bin = create_bin();
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/unref %d bin with children %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters/2;i++) {
+    bin = create_bin_ghostpads();
+    gst_object_unref (GST_OBJECT (bin));
+  }
+  g_print ("create/unref %d bin with children and ghostpads %ld\n", iters/2, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test1();
+  }
+  g_print ("add/remove test1 %d in bin %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test2();
+  }
+  g_print ("add/remove test2 %d in bin %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test3();
+  }
+  g_print ("add/destroy/remove test3 %d in bin %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test4();
+  }
+  g_print ("add/destroy/remove test4 %d in bin %ld\n", iters, vmsize()-usage1);
+
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/testsuite/refcounting/element.c b/testsuite/refcounting/element.c
new file mode 100644 (file)
index 0000000..f61ffbc
--- /dev/null
@@ -0,0 +1,116 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+  GstElement *element;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+  g_print ("starting test\n");
+  usage1 = vmsize();
+
+  element = gst_element_new ();
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("create/unref new element %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+  element = gst_element_new ();
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_object_ref (GST_OBJECT (element));
+  gst_object_sink (GST_OBJECT (element));
+  g_assert (!GST_OBJECT_FLOATING (element));
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("create/ref/sink/unref new element %ld\n", vmsize()-usage1);
+
+
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_ref (GST_OBJECT (element));
+    gst_object_sink (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/ref/sink/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+  element = gst_element_new ();
+  g_assert (!GST_OBJECT_DESTROYED (element));
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (GST_OBJECT_DESTROYED (element));
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("create/destroy/unref new element %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_destroy (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/destroy/unref %d element %ld\n", iters, vmsize()-usage1);
+
+  element = gst_element_new ();
+  gst_object_ref (GST_OBJECT (element));
+  gst_object_unref (GST_OBJECT (element));
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("create/ref/unref/unref new element %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_ref (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/ref/unref/unref %d element %ld\n", iters, vmsize()-usage1);
+
+  element = gst_element_new ();
+  gst_object_ref (GST_OBJECT (element));
+  gst_object_destroy (GST_OBJECT (element));
+  gst_object_unref (GST_OBJECT (element));
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("craete/ref/destroy/unref/unref new element %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_ref (GST_OBJECT (element));
+    gst_object_destroy (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    element = gst_element_new ();
+    gst_object_ref (GST_OBJECT (element));
+    gst_element_set_name (element, "testing123");
+    gst_object_destroy (GST_OBJECT (element));
+    gst_element_set_name (element, "testing123");
+    gst_object_unref (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d elements with name %ld\n", iters, vmsize()-usage1);
+
+  element = gst_element_new ();
+  for (i=0; i<iters;i++) {
+    gst_element_set_name (element, "testing");
+  }
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/testsuite/refcounting/element_pad.c b/testsuite/refcounting/element_pad.c
new file mode 100644 (file)
index 0000000..0f80291
--- /dev/null
@@ -0,0 +1,134 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_element (gchar *padname, GstPadDirection dir)
+{
+  GstElement *element;
+  GstPad *pad;
+
+  element = gst_element_new ();
+  pad = gst_pad_new (padname, dir);
+  gst_element_add_pad (element, pad);
+
+  return element;
+}
+
+int
+main (int argc, gchar *argv[])
+{
+  GstElement *element;
+  GstElement *element2;
+  GstPad *pad;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+
+  g_print ("starting element with pad test with %d iterations\n", iters);
+  usage1 = vmsize();
+
+  element = create_element ("sink", GST_PAD_SINK);
+  pad = gst_element_get_pad (element, "sink");
+  g_assert (GST_OBJECT_FLOATING (element));
+  g_assert (!GST_OBJECT_FLOATING (pad));
+  g_assert (gst_pad_get_parent (pad) == element);
+  gst_object_unref (GST_OBJECT (element));
+  g_print ("create/addpad/unref new element %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/addpad/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    element2 = create_element ("src", GST_PAD_SRC);
+    gst_element_connect (element, "sink", element2, "src");
+    g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+    g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element, "sink")));
+    gst_object_unref (GST_OBJECT (element));
+    g_assert (!GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+    gst_object_unref (GST_OBJECT (element2));
+  }
+  g_print ("create/connect/unref %d elements %ld\n", iters/2, vmsize()-usage1);
+
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    element2 = create_element ("src", GST_PAD_SRC);
+    gst_element_connect (element, "sink", element2, "src");
+    g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+    g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element, "sink")));
+    gst_object_destroy (GST_OBJECT (element));
+    g_assert (GST_OBJECT_DESTROYED (element));
+    g_assert (!GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+    gst_object_unref (GST_OBJECT (element2));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("create/connect/destroy %d elements %ld\n", iters/2, vmsize()-usage1);
+
+  element = create_element ("sink", GST_PAD_SINK);
+  pad = gst_element_get_pad (element, "sink");
+  gst_element_remove_pad (element, pad);
+  g_assert (gst_element_get_pad (element, "sink") == NULL);
+
+  g_print ("pad removal ok %ld\n", vmsize()-usage1);
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    pad = gst_element_get_pad (element, "sink");
+    gst_element_remove_pad (element, pad);
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("pad removal loop %d  %ld\n", iters/2, vmsize()-usage1);
+
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    pad = gst_element_get_pad (element, "sink");
+    gst_object_ref (GST_OBJECT (pad));
+    gst_element_remove_pad (element, pad);
+    g_assert (gst_pad_get_parent (pad) == NULL);
+    gst_object_unref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("pad removal and test loop %d  %ld\n", iters/2, vmsize()-usage1);
+
+  element = create_element ("sink", GST_PAD_SINK);
+  pad = gst_element_get_pad (element, "sink");
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (GST_OBJECT_DESTROYED (element));
+  g_assert (gst_element_get_pad (element, "sink") == NULL);
+  gst_object_unref (GST_OBJECT (element));
+
+  g_print ("pad destroy/removal ok %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    pad = gst_element_get_pad (element, "sink");
+    gst_object_destroy (GST_OBJECT (element));
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("pad destroy/removal loop %d %ld\n", iters/2, vmsize()-usage1);
+
+  for (i=0; i<iters/2; i++) {
+    element = create_element ("sink", GST_PAD_SINK);
+    pad = gst_element_get_pad (element, "sink");
+    gst_object_destroy (GST_OBJECT (pad));
+    g_assert (gst_element_get_pad (element, "sink") == NULL);
+    gst_object_unref (GST_OBJECT (element));
+  }
+  g_print ("pad destroy loop %d %ld\n", iters/2, vmsize()-usage1);
+
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/testsuite/refcounting/mem.c b/testsuite/refcounting/mem.c
new file mode 100644 (file)
index 0000000..8e1c573
--- /dev/null
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int vmsize() {
+  int pid,fd,size,i,mem;
+  char filename[17], buf[256], *ptr, *end;
+
+  pid = getpid();
+  snprintf(filename,17,"/proc/%d/stat",pid);
+  fd = open(filename,O_RDONLY);
+  size = read(fd,buf,240);
+  ptr = buf;
+  for (i=0;i<22;i++)
+    ptr = (char *)strchr(ptr,' ') + 1;
+  end = (char *)strchr(ptr,' ');
+  *end = 0;
+  sscanf(ptr,"%d",&mem);
+  close(fd);
+  return mem;
+}
diff --git a/testsuite/refcounting/mem.h b/testsuite/refcounting/mem.h
new file mode 100644 (file)
index 0000000..28999db
--- /dev/null
@@ -0,0 +1 @@
+int vmsize();
diff --git a/testsuite/refcounting/object.c b/testsuite/refcounting/object.c
new file mode 100644 (file)
index 0000000..477ec9b
--- /dev/null
@@ -0,0 +1,156 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+  GstObject *object, *object2;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+  g_print ("starting test with %d iterations\n", iters);
+  usage1 = vmsize();
+  object = gst_object_new ();
+  gst_object_unref (object);
+  g_print ("create/unref new object %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_unref (object);
+
+  }
+  g_print ("create/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  g_assert (GST_OBJECT_FLOATING (object));
+  gst_object_ref (object);
+  gst_object_sink (object);
+  g_assert (!GST_OBJECT_FLOATING (object));
+  gst_object_unref (object);
+  g_print ("create/ref/sink/unref new object %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_ref (object);
+    gst_object_sink (object);
+    gst_object_unref (object);
+  }
+  g_print ("create/ref/sink/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  g_assert (!GST_OBJECT_DESTROYED (object));
+  gst_object_destroy (object);
+  g_assert (GST_OBJECT_DESTROYED (object));
+  gst_object_unref (object);
+  g_print ("create/destroy/unref new object %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_destroy (object);
+    gst_object_unref (object);
+  }
+  g_print ("destroy/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  gst_object_ref (object);
+  gst_object_unref (object);
+  gst_object_unref (object);
+  g_print ("create/ref/unref/unref new object %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_ref (object);
+    gst_object_unref (object);
+    gst_object_unref (object);
+  }
+  g_print ("create/ref/unref/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  gst_object_ref (object);
+  gst_object_destroy (object);
+  gst_object_unref (object);
+  gst_object_unref (object);
+  g_print ("create/ref/destroy/unref/unref new object %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_ref (object);
+    gst_object_destroy (object);
+    gst_object_unref (object);
+    gst_object_unref (object);
+  }
+  g_print ("create/ref/destroy/unref/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    gst_object_ref (object);
+    gst_object_set_name (object, "testing123");
+    gst_object_destroy (object);
+    gst_object_set_name (object, "testing123");
+    gst_object_unref (object);
+    gst_object_unref (object);
+  }
+  g_print ("create/ref/destroy/unref/unref %d object  with name %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  for (i=0; i<iters;i++) {
+    gst_object_set_name (object, "testing");
+  }
+  gst_object_unref (object);
+  g_print ("create/set name/unref %d object %ld\n", iters, vmsize()-usage1);
+
+  object = gst_object_new ();
+  object2 = gst_object_new ();
+  g_assert (GST_OBJECT_FLOATING (object));
+  g_assert (GST_OBJECT_FLOATING (object2));
+
+  gst_object_set_parent (object, object2);
+  g_assert (GST_OBJECT_FLOATING (object2));
+  g_assert (!GST_OBJECT_FLOATING (object));
+
+  g_print ("parentage flags set_parent ok %ld\n", vmsize()-usage1);
+
+  gst_object_ref (object);
+  gst_object_unparent (object);
+  g_assert (GST_OBJECT_FLOATING (object2));
+  g_assert (!GST_OBJECT_FLOATING (object));
+  g_assert (gst_object_get_parent (object) == NULL);
+
+  g_print ("parentage flags unparent ok %ld\n", vmsize()-usage1);
+
+  gst_object_set_parent (object, object2);
+  g_assert (GST_OBJECT_FLOATING (object2));
+  g_assert (!GST_OBJECT_FLOATING (object));
+  g_assert (gst_object_get_parent (object) == object2);
+
+  gst_object_destroy (object);
+  g_assert (GST_OBJECT_DESTROYED (object));
+  g_assert (!GST_OBJECT_FLOATING (object));
+  g_assert (gst_object_get_parent (object) == NULL);
+  gst_object_unref (object);
+
+  g_print ("parentage flags destroy ok %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    object = gst_object_new ();
+    object2 = gst_object_new ();
+    gst_object_set_parent (object2, object);
+    gst_object_unref (object);
+    gst_object_unref (object2);
+  }
+  g_print ("create/unref %d 2 parented objects %ld\n", iters, vmsize()-usage1);
+
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/testsuite/refcounting/pad.c b/testsuite/refcounting/pad.c
new file mode 100644 (file)
index 0000000..fed2554
--- /dev/null
@@ -0,0 +1,223 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+  GstPad *pad;
+  GstPad *pad2;
+  GstPadTemplate *padtempl;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+  g_print ("starting pad test\n");
+  usage1 = vmsize();
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("create/unref new pad %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  g_assert (GST_OBJECT_FLOATING (pad));
+  gst_object_ref (GST_OBJECT (pad));
+  gst_object_sink (GST_OBJECT (pad));
+  g_assert (!GST_OBJECT_FLOATING (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("create/ref/sink/unref new pad %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_ref (GST_OBJECT (pad));
+    gst_object_sink (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/ref/sink/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  g_assert (!GST_OBJECT_DESTROYED (pad));
+  gst_object_destroy (GST_OBJECT (pad));
+  g_assert (GST_OBJECT_DESTROYED (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("create/destroy/unref pad %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_destroy (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/destroy/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  gst_object_ref (GST_OBJECT (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("create/ref/unref/unref pad %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_ref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/ref/unref/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  gst_object_ref (GST_OBJECT (pad));
+  gst_object_destroy (GST_OBJECT (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("create/ref/destroy/unref/unref pad %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_ref (GST_OBJECT (pad));
+    gst_object_destroy (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/ref/destroy/unref/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    gst_object_ref (GST_OBJECT (pad));
+    gst_pad_set_name (pad, "testing123");
+    gst_object_destroy (GST_OBJECT (pad));
+    gst_pad_set_name (pad, "testing123");
+    gst_object_unref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("create/ref/destroy/unref/unref %d pads %ld with name\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  for (i=0; i<iters;i++) {
+    gst_pad_set_name (pad, "testing");
+  }
+  gst_object_unref (GST_OBJECT (pad));
+  g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+  gst_pad_connect (pad2, pad);
+  g_assert (GST_PAD_CONNECTED (pad));
+  g_assert (GST_PAD_CONNECTED (pad2));
+  gst_pad_disconnect (pad2, pad);
+  g_assert (!GST_PAD_CONNECTED (pad));
+  g_assert (!GST_PAD_CONNECTED (pad2));
+  g_print ("connect/disconnect pad %ld\n", vmsize()-usage1);
+  gst_pad_connect (pad, pad2);
+  g_assert (GST_PAD_CONNECTED (pad));
+  g_assert (GST_PAD_CONNECTED (pad2));
+  gst_pad_disconnect (pad, pad2);
+  g_assert (!GST_PAD_CONNECTED (pad));
+  g_assert (!GST_PAD_CONNECTED (pad2));
+  g_print ("connect/disconnect pad wrong direction %ld\n", vmsize()-usage1);
+
+  gst_object_unref (GST_OBJECT (pad));
+  gst_object_unref (GST_OBJECT (pad2));
+
+  for (i=0; i<iters;i++) {
+    pad = gst_pad_new ("padname", GST_PAD_SINK);
+    pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+    gst_pad_connect (pad2, pad);
+    gst_pad_disconnect (pad2, pad);
+    gst_pad_connect (pad, pad2);
+    gst_pad_disconnect (pad, pad2);
+    gst_object_unref (GST_OBJECT (pad));
+    gst_object_unref (GST_OBJECT (pad2));
+  }
+  g_print ("connect/disconnect %d pads %ld\n", iters, vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+  gst_pad_connect (pad2, pad);
+  g_assert (GST_PAD_CONNECTED (pad2));
+  g_assert (GST_PAD_CONNECTED (pad));
+
+  gst_object_unref (GST_OBJECT (pad2));
+  g_assert (!GST_PAD_CONNECTED (pad));
+  g_assert (!GST_OBJECT_DESTROYED (pad));
+  gst_object_unref (GST_OBJECT (pad));
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+  gst_pad_connect (pad2, pad);
+  g_assert (GST_PAD_CONNECTED (pad2));
+  g_assert (GST_PAD_CONNECTED (pad));
+
+  gst_object_unref (GST_OBJECT (pad));
+  g_assert (!GST_PAD_CONNECTED (pad2));
+  g_assert (!GST_OBJECT_DESTROYED (pad2));
+  gst_object_unref (GST_OBJECT (pad2));
+
+  g_print ("pad unref effects on connect pad ok %ld\n", vmsize()-usage1);
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+  gst_pad_connect (pad2, pad);
+  g_assert (GST_PAD_CONNECTED (pad2));
+  g_assert (GST_PAD_CONNECTED (pad));
+
+  gst_object_destroy (GST_OBJECT (pad2));
+  g_assert (GST_OBJECT_DESTROYED (pad2));
+  g_assert (!GST_OBJECT_DESTROYED (pad));
+  g_assert (!GST_PAD_CONNECTED (pad));
+  gst_object_unref (GST_OBJECT (pad2));
+  g_assert (!GST_OBJECT_DESTROYED (pad));
+  g_assert (!GST_PAD_CONNECTED (pad));
+  gst_object_unref (GST_OBJECT (pad));
+
+  pad = gst_pad_new ("padname", GST_PAD_SINK);
+  pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+  gst_pad_connect (pad2, pad);
+  g_assert (GST_PAD_CONNECTED (pad2));
+  g_assert (GST_PAD_CONNECTED (pad));
+
+  gst_object_destroy (GST_OBJECT (pad));
+  g_assert (GST_OBJECT_DESTROYED (pad));
+  g_assert (!GST_OBJECT_DESTROYED (pad2));
+  g_assert (!GST_PAD_CONNECTED (pad2));
+  gst_object_unref (GST_OBJECT (pad));
+  g_assert (!GST_OBJECT_DESTROYED (pad2));
+  g_assert (!GST_PAD_CONNECTED (pad2));
+  gst_object_unref (GST_OBJECT (pad2));
+
+  g_print ("pad destroy effects on connect pad ok %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    padtempl = gst_padtemplate_new ("sink%d", GST_PAD_SINK, GST_PAD_SOMETIMES, NULL);
+    gst_object_unref (GST_OBJECT (padtempl));
+  }
+  g_print ("%d padtemplates create/unref %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    padtempl = gst_padtemplate_new ("sink%d", GST_PAD_SINK, GST_PAD_SOMETIMES, NULL);
+    pad = gst_pad_new_from_template (padtempl, "sink1");
+    gst_object_unref (GST_OBJECT (pad));
+  }
+  g_print ("%d pads create/unref from padtemplate %ld\n", iters, vmsize()-usage1);
+  
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return vmsize()-usage1;
+}
diff --git a/testsuite/refcounting/thread.c b/testsuite/refcounting/thread.c
new file mode 100644 (file)
index 0000000..f229a54
--- /dev/null
@@ -0,0 +1,281 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_thread (void)
+{
+  GstElement *thread;
+  GstElement *element;
+
+  thread = gst_thread_new ("testthread");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  gst_bin_add (GST_BIN (thread), element);
+  element = gst_element_new ();
+  gst_element_set_name (element, "test2");
+  gst_bin_add (GST_BIN (thread), element);
+
+  return thread;
+}
+
+static GstElement*
+create_thread_ghostpads (void)
+{
+  GstElement *thread;
+  GstElement *element1, *element2;
+
+  thread = gst_thread_new ("testthread");
+  element1 = gst_element_new ();
+  gst_element_set_name (element1, "test1");
+  gst_element_add_pad (element1, gst_pad_new ("src1", GST_PAD_SRC));
+  gst_bin_add (GST_BIN (thread), element1);
+  element2 = gst_element_new ();
+  gst_element_set_name (element2, "test2");
+  gst_element_add_pad (element2, gst_pad_new ("sink1", GST_PAD_SINK));
+  gst_bin_add (GST_BIN (thread), element2);
+  gst_element_connect (element1, "src1", element2, "sink1");
+  gst_element_add_ghost_pad (thread, gst_element_get_pad (element2, "sink1"), "sink1");
+
+  return thread;
+}
+
+static void
+add_remove_test1 (void)
+{
+  GstElement *thread;
+  GstElement *element;
+
+  thread = gst_thread_new ("testthread");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (thread), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  gst_bin_remove (GST_BIN (thread), element);
+
+  gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test2 (void)
+{
+  GstElement *thread;
+  GstElement *element;
+
+  thread = gst_thread_new ("testthread");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  gst_object_ref (GST_OBJECT (element));
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (thread), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  gst_bin_remove (GST_BIN (thread), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+  g_assert (!GST_OBJECT_DESTROYED (element));
+
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (GST_OBJECT_DESTROYED (element));
+  gst_object_unref (GST_OBJECT (element));
+
+  gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test3 (void)
+{
+  GstElement *thread;
+  GstElement *element;
+
+  thread = gst_thread_new ("testthread");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (thread), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (gst_bin_get_by_name (GST_BIN (thread), "test1") == NULL);
+
+  gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test4 (void)
+{
+  GstElement *thread, *thread2;
+  GstElement *element;
+
+  thread = gst_thread_new ("testthread");
+  element = gst_element_new ();
+  gst_element_set_name (element, "test1");
+  g_assert (GST_OBJECT_FLOATING (element));
+  gst_bin_add (GST_BIN (thread), element);
+  g_assert (!GST_OBJECT_FLOATING (element));
+
+  thread2 = create_thread ();
+  g_assert (GST_OBJECT_FLOATING (thread2));
+  gst_bin_add (GST_BIN (thread), thread2);
+  g_assert (!GST_OBJECT_FLOATING (thread2));
+
+  gst_object_destroy (GST_OBJECT (thread2));
+  g_assert (gst_bin_get_by_name (GST_BIN (thread), "testthread") == NULL);
+  gst_object_destroy (GST_OBJECT (element));
+  g_assert (gst_bin_get_by_name (GST_BIN (thread), "test1") == NULL);
+
+  gst_object_unref (GST_OBJECT (thread));
+}
+
+int
+main (int argc, gchar *argv[])
+{
+  GstElement *thread, *element;
+  long usage1;
+  gint i, iters;
+
+  gst_init (&argc, &argv);
+
+  if (argc == 2)
+    iters = atoi (argv[1]);
+  else
+    iters = ITERS;
+
+  g_print ("starting test\n");
+  usage1 = vmsize();
+
+  thread = gst_thread_new ("somethread");
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("create/unref new thread %ld\n", vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+  thread = gst_thread_new ("somethread");
+  g_assert (GST_OBJECT_FLOATING (thread));
+  gst_object_ref (GST_OBJECT (thread));
+  gst_object_sink (GST_OBJECT (thread));
+  g_assert (!GST_OBJECT_FLOATING (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("create/ref/sink/unref new thread %ld\n", vmsize()-usage1);
+
+
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_ref (GST_OBJECT (thread));
+    gst_object_sink (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/ref/sink/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+  thread = gst_thread_new ("somethread");
+  g_assert (!GST_OBJECT_DESTROYED (thread));
+  gst_object_destroy (GST_OBJECT (thread));
+  g_assert (GST_OBJECT_DESTROYED (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("create/destroy/unref new thread %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_destroy (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/destroy/unref %d thread %ld\n", iters, vmsize()-usage1);
+
+  thread = gst_thread_new ("somethread");
+  gst_object_ref (GST_OBJECT (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("create/ref/unref/unref new thread %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_ref (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/ref/unref/unref %d thread %ld\n", iters, vmsize()-usage1);
+
+  thread = gst_thread_new ("somethread");
+  gst_object_ref (GST_OBJECT (thread));
+  gst_object_destroy (GST_OBJECT (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("craete/ref/destroy/unref/unref new thread %ld\n", vmsize()-usage1);
+  
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_ref (GST_OBJECT (thread));
+    gst_object_destroy (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    gst_object_ref (GST_OBJECT (thread));
+    gst_element_set_name (thread, "testing123");
+    gst_object_destroy (GST_OBJECT (thread));
+    gst_element_set_name (thread, "testing123");
+    gst_object_unref (GST_OBJECT (thread));
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("craete/ref/destroy/unref/unref %d threads with name %ld\n", iters, vmsize()-usage1);
+
+  thread = gst_thread_new ("somethread");
+  for (i=0; i<iters;i++) {
+    gst_element_set_name (thread, "testing");
+  }
+  gst_object_unref (GST_OBJECT (thread));
+  g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    thread = gst_thread_new ("somethread");
+    element = gst_element_new ();
+    gst_element_set_name (element, "test1");
+    gst_bin_add (GST_BIN (thread), element);
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/unref %d thread with one element %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    thread = create_thread();
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/unref %d thread with children %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters/2;i++) {
+    thread = create_thread_ghostpads();
+    gst_object_unref (GST_OBJECT (thread));
+  }
+  g_print ("create/unref %d thread with children and ghostpads %ld\n", iters/2, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test1();
+  }
+  g_print ("add/remove test1 %d in thread %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test2();
+  }
+  g_print ("add/remove test2 %d in thread %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test3();
+  }
+  g_print ("add/destroy/remove test3 %d in thread %ld\n", iters, vmsize()-usage1);
+
+  for (i=0; i<iters;i++) {
+    add_remove_test4();
+  }
+  g_print ("add/destroy/remove test4 %d in thread %ld\n", iters, vmsize()-usage1);
+
+  g_print ("leaked: %ld\n", vmsize()-usage1);
+
+  return (vmsize()-usage1 ? -1 : 0);
+}
index e5db16a..beeec25 100644 (file)
@@ -9,4 +9,6 @@ Makefile.in
 gstreamer-launch
 gstreamer-register
 gstreamer-inspect
+gstreamer-compprep
+gstreamer-complete
 *.xml
index f723d5d..e0bbeeb 100644 (file)
@@ -1,4 +1,5 @@
-bin_PROGRAMS = gstreamer-launch gstreamer-register gstreamer-inspect
+bin_PROGRAMS = gstreamer-launch gstreamer-register gstreamer-inspect \
+       gstreamer-compprep gstreamer-complete
 
 man_MANS = gstreamer-launch.1 gstreamer-register.1 gstreamer-inspect.1
 
diff --git a/tools/gstreamer-complete.c b/tools/gstreamer-complete.c
new file mode 100644 (file)
index 0000000..aaf70ac
--- /dev/null
@@ -0,0 +1,203 @@
+#include <stdio.h>
+#include <string.h>
+#include <parser.h>
+#include <glib.h>
+
+#include "config.h"
+
+typedef struct {
+  gchar *name;
+  GSList *srcpads;
+  GSList *sinkpads;
+  GSList *srcpadtemplates;
+  GSList *sinkpadtemplates;
+  GSList *arguments;
+} comp_element;
+
+enum {
+  ARG_INT,
+  ARG_FILENAME,
+  ARG_ENUM
+};
+
+typedef struct {
+  gchar *name;
+  int type;
+  GSList *enums;
+} comp_argument;
+
+typedef struct {
+  gint value;
+  gchar *nick;
+} enum_value;
+
+
+void print_match_list (gchar *prefix, int len, GSList *wordlist) {
+  GSList *words = wordlist;
+
+  while (words) {
+    if (!len || !strncmp((gchar *)(words->data), prefix, len))
+      printf("%s\n",(gchar *)(words->data));
+    words = g_slist_next (words);
+  }
+}
+
+int match_element (comp_element *element, gchar *name) {
+  return strcmp(element->name,name);
+}
+
+int main(int argc,char *argv[]) {
+  xmlDocPtr doc;
+  xmlNodePtr rootnode, elementnode, propnode, argnode;
+  GList *element_list = NULL;
+  comp_element *element;
+  GSList *element_names = NULL;
+  comp_argument *argument;
+  enum_value *option;
+
+  gchar *prev_word = argv[3];
+  gchar *partial_word = argv[2];
+  int partial_len = strlen(partial_word);
+  GList *elements;
+  GSList *pads;
+  int num_pads;
+  GSList *args;
+  gchar *word;
+  GSList *words = NULL;
+
+  /***** Loading the completion information from the registry *****/
+
+  doc = xmlParseFile (GST_CONFIG_DIR "/compreg.xml");
+  rootnode = doc->xmlRootNode;
+
+  elementnode = rootnode->xmlChildrenNode;
+  while (elementnode) {
+    if (!strcmp(elementnode->name, "element")) {
+      element = g_new0(comp_element,1);
+      propnode = elementnode->xmlChildrenNode;
+      while (propnode) {
+
+        if (!strcmp(propnode->name, "name")) {
+          element->name = xmlNodeGetContent(propnode);
+//fprintf(stderr,element->name);
+        } else if (!strcmp(propnode->name, "srcpad")) {
+          element->srcpads = g_slist_prepend(element->srcpads, xmlNodeGetContent(propnode));
+//fprintf(stderr,".");
+        } else if (!strcmp(propnode->name, "sinkpad")) {
+          element->sinkpads = g_slist_prepend(element->sinkpads, xmlNodeGetContent(propnode));
+        } else if (!strcmp(propnode->name, "srcpadtemplate")) {
+          element->srcpadtemplates = g_slist_prepend(element->srcpadtemplates, xmlNodeGetContent(propnode));
+//fprintf(stderr,".");
+        } else if (!strcmp(propnode->name, "sinkpad")) {
+          element->sinkpadtemplates = g_slist_prepend(element->sinkpadtemplates, xmlNodeGetContent(propnode));
+        } else if (!strcmp(propnode->name, "argument")) {
+          argument = g_new0(comp_argument,1);
+          argument->name = xmlNodeGetContent(propnode);
+          argument->type = ARG_INT;
+
+          // walk through the values data
+          argnode = propnode->xmlChildrenNode;
+          while (argnode) {
+            if (!strcmp(argnode->name, "filename")) {
+              argument->type = ARG_FILENAME;
+            } else if (!strcmp(argnode->name,"option")) {
+              argument->type = ARG_ENUM;
+              option = g_new0(enum_value,1);
+              sscanf(xmlNodeGetContent(argnode),"%d",&option->value);
+              argument->enums = g_slist_prepend (argument->enums, option);
+            }
+            argnode = argnode->next;
+          }
+
+          element->arguments = g_slist_prepend(element->arguments, argument);
+        }
+
+        propnode = propnode->next;
+      }
+      element_list = g_list_prepend(element_list, element);
+      element_names = g_slist_prepend(element_names, element->name);
+    }
+    elementnode = elementnode->next;
+  }
+
+
+
+  /***** Completion *****/
+
+  /* The bulk of the work is in deciding exactly which words are an option. */
+
+  // if we're right at the beginning, with -launch in the first word
+  if (strstr(prev_word,"-launch")) {
+    // print out only elements with no sink pad or padtemplate
+    elements = element_list;
+    while (elements) {
+      element = (comp_element *)(elements->data);
+      if (!element->sinkpads && !element->sinkpadtemplates)
+        words = g_slist_prepend (words, element->name);
+      elements = g_list_next(elements);
+    }
+  }
+
+  // if the previous word is a connection
+  if (strchr(prev_word, '!')) {
+    // print out oly elements with a sink pad or template
+    elements = element_list;
+    while (elements) {
+      element = (comp_element *)(elements->data);
+      if (element->sinkpads || element->sinkpadtemplates)
+        words = g_slist_prepend (words, element->name);
+      elements = g_list_next (elements);
+    }
+  }
+
+  // if the partial word is an argument, and it's an enum
+  if (strchr(prev_word,'=')) {
+    fprintf(stderr,"it's an arg, but dunno what element yet\n");
+  }
+
+  // if the previous word is an element, we need to list both pads and arguments
+  if ((elements = g_list_find_custom(element_list, prev_word, (GCompareFunc)match_element))) {
+    element = elements->data;
+    // zero the numpads list so we can count them
+    num_pads = 0;
+
+    // pads
+    pads = element->srcpads;
+    while (pads) {
+      num_pads++;
+      words = g_slist_prepend (words, g_strdup_printf("%s!",(gchar *)(pads->data)));
+      pads = g_slist_next (pads);
+    }
+
+    // padtemplates
+    pads = element->srcpadtemplates;
+    while (pads) {
+      num_pads++;
+      word = g_strdup_printf("%s!",(gchar *)(pads->data));
+      if (!g_slist_find_custom(words,word,(GCompareFunc)strcmp))
+        words = g_slist_prepend (words, word);
+      pads = g_slist_next (pads);
+    }
+
+    // if there is only one pad, add '!' to the list of completions
+    if (num_pads == 1) {
+      words = g_slist_prepend (words, "!");
+    }
+
+    // arguments
+    args = element->arguments;
+    while (args) {
+      argument = (comp_argument *)(args->data);
+      word = strstr(argument->name,"::")+2;
+      words = g_slist_prepend (words, g_strdup_printf("%s=",word));
+      words = g_slist_prepend (words, g_strdup_printf("%s=...",word));
+      args = g_slist_next (args);
+    }
+  }
+
+
+  /* The easy part is ouptuting the correct list of possibilities. */
+  print_match_list (partial_word, partial_len, words);
+
+  return 0;
+}
diff --git a/tools/gstreamer-compprep.c b/tools/gstreamer-compprep.c
new file mode 100644 (file)
index 0000000..c0c3e3a
--- /dev/null
@@ -0,0 +1,91 @@
+#include <gst/gst.h>
+#include "config.h"
+
+int main(int argc,char *argv[]) {
+  xmlDocPtr doc;
+  xmlNodePtr factorynode, padnode, argnode, optionnode;
+  GList *plugins, *factories, *padtemplates, *pads;
+  GstPlugin *plugin;
+  GstElementFactory *factory;
+  GstElement *element;
+  GstPad *pad;
+  GstPadTemplate *padtemplate;
+  GtkArg *args;
+  guint32 *flags;
+  gint num_args,i;
+
+  gst_debug_set_categories(0);
+  gst_info_set_categories(0);
+  gst_init(&argc,&argv);
+
+  doc = xmlNewDoc("1.0");
+  doc->xmlRootNode = xmlNewDocNode(doc, NULL, "GST-CompletionRegistry", NULL);
+
+  plugins = gst_plugin_get_list();
+  while (plugins) {
+    plugin = (GstPlugin *)(plugins->data);
+    plugins = g_list_next (plugins);
+
+    factories = gst_plugin_get_factory_list(plugin);
+    while (factories) {
+      factory = (GstElementFactory *)(factories->data);
+      factories = g_list_next (factories);
+
+      factorynode = xmlNewChild (doc->xmlRootNode, NULL, "element", NULL);
+      xmlNewChild (factorynode, NULL, "name", factory->name);
+
+      element = gst_elementfactory_create(factory,"element");
+      if (element == NULL) {
+        fprintf(stderr,"couldn't construct element from factory %s\n",factory->name);
+        return 1;
+      }
+
+      // write out the padtemplates
+      padtemplates = factory->padtemplates;
+      while (padtemplates) {
+        padtemplate = (GstPadTemplate *)(padtemplates->data);
+        padtemplates = g_list_next (padtemplates);
+
+        if (padtemplate->direction == GST_PAD_SRC)
+          padnode = xmlNewChild (factorynode, NULL, "srcpadtemplate", padtemplate->name_template);
+        else if (padtemplate->direction == GST_PAD_SINK)
+          padnode = xmlNewChild (factorynode, NULL, "sinkpadtemplate", padtemplate->name_template);
+      }
+
+      pads = gst_element_get_pad_list (element);
+      while (pads) {
+        pad = (GstPad *)(pads->data);
+        pads = g_list_next (pads);
+
+        if (GST_PAD_DIRECTION(pad) == GST_PAD_SRC)
+          padnode = xmlNewChild (factorynode, NULL, "srcpad", GST_PAD_NAME(pad));
+        else if (GST_PAD_DIRECTION(pad) == GST_PAD_SINK)
+          padnode = xmlNewChild (factorynode, NULL, "sinkpad", GST_PAD_NAME(pad));
+      }
+
+      // write out the args
+      args = gtk_object_query_args(GTK_OBJECT_TYPE(element), &flags, &num_args);
+      for (i=0;i<num_args;i++) {
+        argnode = xmlNewChild (factorynode, NULL, "argument", args[i].name);
+        if (args[i].type == GST_TYPE_FILENAME) {
+          xmlNewChild (argnode, NULL, "filename", NULL);
+        } else if (GTK_FUNDAMENTAL_TYPE (args[i].type) == GTK_TYPE_ENUM) {
+          GtkEnumValue *values;
+          gint j;
+
+          values = gtk_type_enum_get_values (args[i].type);
+          for (j=0;values[j].value_name;j++) {
+            gchar *value = g_strdup_printf("%d",values[j].value);
+            optionnode = xmlNewChild (argnode, NULL, "option", value);
+            xmlNewChild (optionnode, NULL, "value_nick", values[j].value_nick);
+            g_free(value);
+          }
+        }
+      }
+    }
+  }
+
+  xmlSaveFile(GST_CONFIG_DIR "/compreg.xml",doc);
+
+  return 0;
+}
index 3c45597..81103f5 100644 (file)
@@ -83,6 +83,8 @@ print_element_info (GstElementFactory *factory)
   GtkArg *args;
   guint32 *flags;
   gint num_args,i;
+  GList *children;
+  GstElement *child;
   gboolean have_flags;
 
   element = gst_elementfactory_create(factory,"element");
@@ -150,7 +152,7 @@ print_element_info (GstElementFactory *factory)
       printf("\n");
     }
   } else
-    printf("  none\n\n");
+    printf("  none\n");
 
   have_flags = FALSE;
 
@@ -173,40 +175,45 @@ print_element_info (GstElementFactory *factory)
   }
   if (!have_flags)
     printf("  no flags set\n");
-  printf("\n");
 
 
-  printf("Element Implementation:\n");
+
+  printf("\nElement Implementation:\n");
+
   if (element->loopfunc)
-    printf("  loopfunc()-based element\n");
+    printf("  loopfunc()-based element: %s\n",GST_DEBUG_FUNCPTR_NAME(element->loopfunc));
   else
     printf("  No loopfunc(), must be chain-based or not configured yet\n");
-  if (gstelement_class->change_state)
-    printf("  Has change_state() function\n");
-  else
-    printf("  No change_state() class function\n");
-  if (gstobject_class->save_thyself)
-    printf("  Has custom save_thyself() class function\n");
-  if (gstobject_class->restore_thyself)
-    printf("  Has custom restore_thyself() class function\n");
-  printf("\n");
 
+  printf("  Has change_state() function: %s\n",
+         GST_DEBUG_FUNCPTR_NAME(gstelement_class->change_state));
+  printf("  Has custom save_thyself() function: %s\n",
+         GST_DEBUG_FUNCPTR_NAME(gstobject_class->save_thyself));
+  printf("  Has custom restore_thyself() function: %s\n",
+         GST_DEBUG_FUNCPTR_NAME(gstobject_class->restore_thyself));
 
-  printf("Pads:\n");
+
+
+  printf("\nPads:\n");
   if (element->numpads) {
     pads = gst_element_get_pad_list(element);
     while (pads) {
       pad = GST_PAD(pads->data);
       pads = g_list_next(pads);
-      realpad = GST_REAL_PAD(pad);
+      realpad = GST_PAD_REALIZE(pad);
 
       if (gst_pad_get_direction(pad) == GST_PAD_SRC)
-        printf("  SRC: '%s'\n",gst_pad_get_name(pad));
+        printf("  SRC: '%s'",gst_pad_get_name(pad));
       else if (gst_pad_get_direction(pad) == GST_PAD_SINK)
-        printf("  SINK: '%s'\n",gst_pad_get_name(pad));
+        printf("  SINK: '%s'",gst_pad_get_name(pad));
       else
         printf("  UNKNOWN!!!: '%s'\n",gst_pad_get_name(pad));
 
+      if (GST_IS_GHOST_PAD(pad))
+        printf(", ghost of real pad %s:%s\n",GST_DEBUG_PAD_NAME(realpad));
+      else
+        printf("\n");
+
       printf("    Implementation:\n");
       if (realpad->chainfunc)
         printf("      Has chainfunc(): %s\n",GST_DEBUG_FUNCPTR_NAME(realpad->chainfunc));
@@ -216,7 +223,7 @@ print_element_info (GstElementFactory *factory)
         printf("      Has getregionfunc(): %s\n",GST_DEBUG_FUNCPTR_NAME(realpad->getregionfunc));
       if (realpad->qosfunc)
         printf("      Has qosfunc(): %s\n",GST_DEBUG_FUNCPTR_NAME(realpad->qosfunc));
-      if (realpad->eosfunc) {
+      if (realpad->eosfunc != gst_pad_eos_func) {
         printf("      Has eosfunc(): %s\n",GST_DEBUG_FUNCPTR_NAME(realpad->eosfunc));
       }
 
@@ -243,13 +250,13 @@ print_element_info (GstElementFactory *factory)
          caps = caps->next;
         }
       }
-
-      printf("\n");
     }
   } else
-    printf("  none\n\n");
+    printf("  none\n");
+
+
 
-  printf("Element Arguments:\n");
+  printf("\nElement Arguments:\n");
   args = gtk_object_query_args(GTK_OBJECT_TYPE(element), &flags, &num_args);
   for (i=0;i<num_args;i++) {
 
@@ -291,6 +298,20 @@ print_element_info (GstElementFactory *factory)
   if (num_args == 0) g_print ("  none");
   printf("\n");
 
+
+
+  // for compound elements
+  if (GST_IS_BIN(element)) {
+    printf("\nChildren:\n");
+    children = gst_bin_get_list(GST_BIN(element));
+    while (children) {
+      child = GST_ELEMENT (children->data);
+      children = g_list_next (children);
+
+      g_print("  %s\n",GST_ELEMENT_NAME(child));
+    }
+  }
+
   return 0;
 }