Merged from INCSCHED on 200505251!!!
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 320b264a344ef904eaa0d6696df7323c103d5916..a7d8dfa5bc30fa2a84bc82e2e0e36deba486d70f 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 2e4f2e612a8f5df601fb9764d190e2a82069cf20..4105ade405f9f69ad0de6df796da5a2433bccce1 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 ebdf9fbc8ad5531b7643382594c9a34211532c00..14cbc0de7f82d75f759a5e112506bb3112852c3f 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 e674cdf1bd95ef40aa57ca591637e5ac1e45010a..1a0a240ddb9ec3661e48b061ac56d63e46787ba3 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 17c1c532b5a752717e27c4e566748deaa3d39d39..5f56a4d4c38dbff644b46d8a474d0d727595f5f3 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 4e5e52dbaf16bf3735056c38bc99d49f9a8d4e52..8131449eaae5bd3b413e22cc85ff6688113104dc 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 05b2defa61046294c8c833e85ab3e7612f78f117..f1471bdafbbdf245c3494afdae3de4fa2911d161 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 dfda3f403e8bfc4c9e984ec37b1327142f0ad2bc..197eaebd6c6098044ada33c093b01915a445dfad 100644 (file)
@@ -46,3 +46,8 @@ The <classname>GstFakeSrc</classname> generates empty buffers. (fakesrc)
 
 </para>
 
+<!-- ##### ARG GstFakeSrc:eos ##### -->
+<para>
+
+</para>
+
index a9e66520b47f2735f00c1e728ddd391b947c6c9a..bc4f3af83920a3908de04384db0d193b0a8d17d3 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 c251eabb68f5fc73e52c33b88ff4ceb3026e0a94..a970883560fd4ea027888fc06080fff218731a6f 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 e9135fb8d22479608811406ee0c7192d1bf378da..70ac4b7a2bcd513f20f3b2f93210ab4f3e40e90d 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 205d0738ab533e38ef4211be7fd2d8be2fe0d955..4461d4796cd5521705a71ce6a12425e95c0a7804 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 cfd5ac69a80f579cce5f31f2212aa77387db9dc5..edd8c0df7f0ae134a0cfdc27fc317ef8e699d67d 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 8050727ae134a3aa798227c70a2bda85923aa34d..043317a262f4a7da6bd21d9d31c93b8c1d91e9e1 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 11403a069df30aae87966a13149cfa964e02b717..3edf83e78a7e897495fe01b3046015d6633eac0f 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 c544f7f1899fd80df54953f20cf255c1d5264708..cbfc798fa1aa069a1b8b2ff0d998c1fed9d9f0be 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 2de2b3ee61cf3e95b90ad107a2657a66dc06e5b4..478dba0d35b2f27332567a3e988e28a2f4b72f07 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 d48b1abbdcc0996661afc7f8efdf6417b996c362..d95d7cf736c7b1028e7869deb8e496a4b8d982e2 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 5fa6af21715c75aaa0625312b3c5542bf8d236d1..97570bbb8f21d8d4a5573654712d78756e217137 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 a795c1932c65795a5461ec69c9d0423b46b5d3ca..ba92f631b636acfdc6da092c46af039f0ef7a017 100644 (file)
@@ -65,6 +65,7 @@ struct _GstFakeSrc {
   GstElement element;
 
   gboolean loop_based;
+  gboolean eos;
   gint numsrcpads;
   GSList *srcpads;
   GstFakeSrcOutputType output;
index 8cddd5d7b19b3d678b1edd4ac901e4cea2e2323f..6a00e1eef0e34482b723f68cdd2c245f4a659415 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 be7eeb4faa0407032ef055c1215b5d1c78c19ea7..e859b04392764dfff25234d60372a39e454c5dd4 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 94a1444f2ed2542089fb88bad14c83b7150cd00f..73bdb0b84c44a8a3d53a06f862ab049df4a8dacc 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 dc0331e07e864e8e86795fac1999f2835767e314..a45f134896d794060f78360a5320d554315e6df0 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 23b826fc68031cb807d52b868968d41352eb82cf..da5d8aa83d154ac2a526a9ee4eee6664b1cdc07e 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 23f68e73a0088f0588abe4f719b4d8d7e7ab5ce6..7a44084ca6a26fd47a6561d9bfb68aa5bca13087 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 df122b58b24146caa859da1092c7f8a10fc44f2a..0ef1c554362ab97cc24d487b9990877425cdad39 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 8040baf339215b0d8ead84c69926527c6a7b79cc..0c3caad5b80c48d3ae3ed79fed1c8c86c5a1d616 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 7241b406caab18dc34ca3d42d289fbce9807ae77..37e5e031846a2a35daac7cf01ea9e9b8b9a97046 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 */
@@ -254,6 +310,36 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
   gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_PAD], 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
@@ -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 cc296c941f515254f9cc58ddfe1291434dea5eb7..212dd4cdc6777a555b6773e2694ba440a9250e06 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 997cb20553a96728344c7b6ee676483b9c866118..9c4bc42e7b7f12d96a6957a1f1d3234011a7f195 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 15263722c4c9828c4ce7c32d210d5a59a3e71946..46ccbde76b8b2c497417c4d1a5e3621b3d1b4d46 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 620d809dde1995f178c0d283d35a4fa56b848aa9..71fdba9f4cb06bb34ac4ac4d7c5052ce577d7246 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 2e7eafb8854b5fc8e38ab8017a17a08439604167..82c7e2b0f540baec66d55c8656c2d0f05d4932a3 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);
 }
 
 /**
@@ -136,6 +147,122 @@ gst_object_new (void)
   return GST_OBJECT (gtk_type_new (gst_object_get_type ()));
 }
 
+/**
+ * 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
@@ -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 9e1e6bb95a9bbf810150f2716276bc755df88847..f7e095f614d1a6324de2830b44a72c0e3185d773 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 48bd1e376c676047516f0c9b5d3ea647b17238f5..69913d25ce50c1fb8285a4ef798d55653c4807c8 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 14731e0f253e6e285ed223c7fb3e9f0e2c986bd8..c5d7224529c221727e9c6c354a846a5bdba3e716 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 f2772d488d4f6bb1c458600b6e3c4124fa77c8b6..f967add7ce2143b9dd7e1005d701fd6f5d039fc9 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 25d5a24cd4d27d1b6aaa7fa90b9a43eab53c63dc..380b531199813f788826b50a7912de2a88fd5931 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 37a4f7f3cb32618462d448a725f7eec839796377..755c8f8c2e2441f4249e3a211e9b84b1d071487a 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 606346735bc5d13d09d681094490223d47d7394a..085d5ac122f3970beab6b1b68ada3bcf8f72d583 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 e4e1d79b62ade0808281e20f70dd6232f4dfa854..0795c18cd07822eae893dddc280149a93aa66c20 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 5cfbfff80213486c29b016fe7068a67b33bb2e45..cdc9052219ce57fada45e8e03bae7c45de1a0203 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 1bdea99d0be1ed8ab29376085317462d1d981873..8f91ff32d766577885aaeb23bdf257919a9961ac 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",
@@ -44,15 +45,24 @@ enum {
   LAST_SIGNAL
 };
 
+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("