summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Walthinsen <omega@temple-baptist.org>2001-05-25 21:00:07 +0000
committerErik Walthinsen <omega@temple-baptist.org>2001-05-25 21:00:07 +0000
commit4a583683e5cdf35d6f059952cbae4416120f8749 (patch)
treeae6079f992bebb3fb51ac8b97f2a16d8ea0ef64c
parent54271eca8ec659e79199f587de00fcbff0dea826 (diff)
Merged from INCSCHED on 200505251!!!INCSCHED1-200105251
Original commit message from CVS: Merged from INCSCHED on 200505251!!!
-rw-r--r--.gitignore2
-rw-r--r--AUTHORS2
-rw-r--r--Makefile.am7
-rwxr-xr-xautogen.sh15
-rw-r--r--configure.in77
-rw-r--r--docs/gst/tmpl/cothreads.sgml2
-rw-r--r--docs/gst/tmpl/gstelement.sgml18
-rw-r--r--docs/gst/tmpl/gstfakesrc.sgml5
-rw-r--r--docs/gst/tmpl/gstthread.sgml2
-rw-r--r--docs/random/matth/scheduling.txt125
-rw-r--r--examples/Makefile.am2
-rw-r--r--examples/autoplug/autoplug.c210
-rw-r--r--examples/mixer/mixer.c155
-rw-r--r--gst/Makefile.am3
-rw-r--r--gst/autoplug/Makefile.am10
-rw-r--r--gst/autoplug/autoplugtest.c92
-rw-r--r--gst/autoplug/gstautoplugcache.c371
-rw-r--r--gst/autoplug/gstautoplugger.c606
-rw-r--r--gst/autoplug/gststaticautoplug.c4
-rw-r--r--gst/autoplug/gststaticautoplugrender.c18
-rw-r--r--gst/cothreads.c93
-rw-r--r--gst/cothreads.h19
-rw-r--r--gst/elements/gstfakesrc.c23
-rw-r--r--gst/elements/gstfakesrc.h1
-rw-r--r--gst/elements/gstsinesrc.c2
-rw-r--r--gst/gst.c32
-rw-r--r--gst/gst.h2
-rw-r--r--gst/gstbin.c532
-rw-r--r--gst/gstbin.h15
-rw-r--r--gst/gstbuffer.c2
-rw-r--r--gst/gstcaps.c12
-rw-r--r--gst/gstclock.c17
-rw-r--r--gst/gstelement.c272
-rw-r--r--gst/gstelement.h66
-rw-r--r--gst/gstelementfactory.c12
-rw-r--r--gst/gstinfo.c340
-rw-r--r--gst/gstinfo.h232
-rw-r--r--gst/gstobject.c165
-rw-r--r--gst/gstobject.h40
-rw-r--r--gst/gstpad.c248
-rw-r--r--gst/gstpad.h32
-rw-r--r--gst/gstpipeline.c19
-rw-r--r--gst/gstprops.c23
-rw-r--r--gst/gstqueue.c251
-rw-r--r--gst/gstqueue.h18
-rw-r--r--gst/gstscheduler.c850
-rw-r--r--gst/gstscheduler.h99
-rw-r--r--gst/gstthread.c474
-rw-r--r--gst/gstthread.h10
-rw-r--r--gst/gsttype.c8
-rw-r--r--gst/gsttypefind.c18
-rw-r--r--gst/gsttypes.h17
-rw-r--r--gst/gstxml.c2
-rw-r--r--gstplay/Makefile.am1
-rw-r--r--gstplay/gstmediaplay.c11
-rw-r--r--gstplay/gstmediaplay.glade2
-rw-r--r--gstplay/gstplay.c184
-rw-r--r--gstplay/gstplay.h8
-rw-r--r--gstplay/gstplayprivate.h5
-rw-r--r--gstreamer-uninstalled.pc.in11
-rw-r--r--gstreamer.pc.in11
-rw-r--r--gstreamer.spec.in1
-rw-r--r--libs/idct/gstidct.c14
-rw-r--r--plugins/elements/gstfakesrc.c23
-rw-r--r--plugins/elements/gstfakesrc.h1
-rw-r--r--plugins/elements/gstqueue.c251
-rw-r--r--plugins/elements/gstqueue.h18
-rw-r--r--plugins/elements/gstsinesrc.c2
-rw-r--r--test/.gitignore1
-rw-r--r--test/Makefile.am12
-rw-r--r--test/avi2mpg.c2
-rw-r--r--test/cobin.c2
-rw-r--r--test/dvshow.c2
-rw-r--r--test/fake.c4
-rw-r--r--test/mpeg2parse2.c1
-rw-r--r--test/mpeg2parse3.c118
-rw-r--r--test/mpeg2parse4.c224
-rw-r--r--test/video2mp1.c2
-rw-r--r--test/videotest2.c2
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/incsched.c135
-rw-r--r--tests/mp1vid.c78
-rw-r--r--tests/old/examples/Makefile.am2
-rw-r--r--tests/old/examples/autoplug/autoplug.c210
-rw-r--r--tests/old/examples/mixer/mixer.c155
-rw-r--r--tests/old/testsuite/refcounting/Makefile.am18
-rw-r--r--tests/old/testsuite/refcounting/bin.c272
-rw-r--r--tests/old/testsuite/refcounting/element.c116
-rw-r--r--tests/old/testsuite/refcounting/element_pad.c134
-rw-r--r--tests/old/testsuite/refcounting/mem.c22
-rw-r--r--tests/old/testsuite/refcounting/mem.h1
-rw-r--r--tests/old/testsuite/refcounting/object.c156
-rw-r--r--tests/old/testsuite/refcounting/pad.c223
-rw-r--r--tests/old/testsuite/refcounting/thread.c281
-rw-r--r--tests/reaping.c35
-rw-r--r--tests/states.c12
-rw-r--r--tests/threadlock.c51
-rw-r--r--testsuite/refcounting/Makefile.am18
-rw-r--r--testsuite/refcounting/bin.c272
-rw-r--r--testsuite/refcounting/element.c116
-rw-r--r--testsuite/refcounting/element_pad.c134
-rw-r--r--testsuite/refcounting/mem.c22
-rw-r--r--testsuite/refcounting/mem.h1
-rw-r--r--testsuite/refcounting/object.c156
-rw-r--r--testsuite/refcounting/pad.c223
-rw-r--r--testsuite/refcounting/thread.c281
-rw-r--r--tools/.gitignore2
-rw-r--r--tools/Makefile.am3
-rw-r--r--tools/gstreamer-complete.c203
-rw-r--r--tools/gstreamer-compprep.c91
-rw-r--r--tools/gstreamer-inspect.c65
111 files changed, 8347 insertions, 1730 deletions
diff --git a/.gitignore b/.gitignore
index 320b264a3..a7d8dfa5b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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 2e4f2e612..4105ade40 100644
--- 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
diff --git a/Makefile.am b/Makefile.am
index ebdf9fbc8..14cbc0de7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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)
diff --git a/autogen.sh b/autogen.sh
index e674cdf1b..1a0a240dd 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -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
diff --git a/configure.in b/configure.in
index 17c1c532b..5f56a4d4c 100644
--- a/configure.in
+++ b/configure.in
@@ -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])
diff --git a/docs/gst/tmpl/cothreads.sgml b/docs/gst/tmpl/cothreads.sgml
index 4e5e52dba..8131449ea 100644
--- a/docs/gst/tmpl/cothreads.sgml
+++ b/docs/gst/tmpl/cothreads.sgml
@@ -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>
diff --git a/docs/gst/tmpl/gstelement.sgml b/docs/gst/tmpl/gstelement.sgml
index 05b2defa6..f1471bdaf 100644
--- a/docs/gst/tmpl/gstelement.sgml
+++ b/docs/gst/tmpl/gstelement.sgml
@@ -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>
diff --git a/docs/gst/tmpl/gstfakesrc.sgml b/docs/gst/tmpl/gstfakesrc.sgml
index dfda3f403..197eaebd6 100644
--- a/docs/gst/tmpl/gstfakesrc.sgml
+++ b/docs/gst/tmpl/gstfakesrc.sgml
@@ -46,3 +46,8 @@ The <classname>GstFakeSrc</classname> generates empty buffers. (fakesrc)
</para>
+<!-- ##### ARG GstFakeSrc:eos ##### -->
+<para>
+
+</para>
+
diff --git a/docs/gst/tmpl/gstthread.sgml b/docs/gst/tmpl/gstthread.sgml
index a9e66520b..bc4f3af83 100644
--- a/docs/gst/tmpl/gstthread.sgml
+++ b/docs/gst/tmpl/gstthread.sgml
@@ -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
index 000000000..7b82d1da4
--- /dev/null
+++ b/docs/random/matth/scheduling.txt
@@ -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)
diff --git a/examples/Makefile.am b/examples/Makefile.am
index c251eabb6..a97088356 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -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
diff --git a/examples/autoplug/autoplug.c b/examples/autoplug/autoplug.c
index e9135fb8d..70ac4b7a2 100644
--- a/examples/autoplug/autoplug.c
+++ b/examples/autoplug/autoplug.c
@@ -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);
}
diff --git a/examples/mixer/mixer.c b/examples/mixer/mixer.c
index 205d0738a..4461d4796 100644
--- a/examples/mixer/mixer.c
+++ b/examples/mixer/mixer.c
@@ -4,10 +4,13 @@
* demonstrates the adder plugin and the volume envelope plugin
* work in progress but do try it out
*
- * Latest change : 16/04/2001
- * multiple input channels allowed
- * volume envelope adapted
- * Version : 0.3
+ * Latest change : 28/04/2001
+ * trying to adapt to incsched
+ * delayed start for channels > 1
+ * now works by quickhacking the
+ * adder plugin to set
+ * GST_ELEMENT_COTHREAD_STOPPING
+ * Version : 0.5
*/
#include <stdlib.h>
@@ -15,8 +18,10 @@
#include "mixer.h"
#include <unistd.h>
+//#define WITH_BUG
+//#define WITH_BUG2
//#define DEBUG
-
+//#define AUTOPLUG /* define if you want autoplugging of input channels */
/* function prototypes */
input_channel_t* create_input_channel (int id, char* location);
@@ -35,55 +40,50 @@ void eos(GstElement *element)
// playing = FALSE;
}
-static void
-gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
-{
- GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
-
- *(gboolean *)data = TRUE;
-}
-
static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element)
{
- gboolean found = FALSE;
GstElement *typefind;
+ GstElement *pipeline;
GstCaps *caps = NULL;
- GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
- GST_ELEMENT_NAME(element), &found);
+ GST_DEBUG (0,"GstPipeline: typefind for element \"%s\"\n",
+ GST_ELEMENT_NAME(element));
+
+ pipeline = gst_pipeline_new ("autoplug_pipeline");
typefind = gst_elementfactory_make ("typefind", "typefind");
g_return_val_if_fail (typefind != NULL, FALSE);
- gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
- GTK_SIGNAL_FUNC (gst_play_have_type), &found);
-
gst_pad_connect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_add (bin, typefind);
+ gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (bin));
- gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
// push a buffer... the have_type signal handler will set the found flag
- gst_bin_iterate (bin);
+ gst_bin_iterate (GST_BIN (pipeline));
- gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
+ gst_element_set_state (pipeline, GST_STATE_NULL);
caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
gst_pad_disconnect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_remove (bin, typefind);
+ gst_bin_remove (GST_BIN (pipeline), GST_ELEMENT (bin));
gst_object_unref (GST_OBJECT (typefind));
+ gst_object_unref (GST_OBJECT (pipeline));
return caps;
}
int main(int argc,char *argv[])
{
- int i;
+ int i, j;
int num_channels;
+ gboolean done;
char buffer[20];
@@ -108,38 +108,41 @@ int main(int argc,char *argv[])
/* set up output channel and main bin */
/* create adder */
- adder = gst_elementfactory_make("adder", "adderel");
+ adder = gst_elementfactory_make ("adder", "adderel");
/* create an audio sink */
- audiosink = gst_elementfactory_make("esdsink", "play_audio");
+ audiosink = gst_elementfactory_make ("esdsink", "play_audio");
/* create main bin */
- main_bin = gst_bin_new("bin");
+ main_bin = gst_pipeline_new("bin");
/* connect adder and output to bin */
-
- gst_bin_add(GST_BIN(main_bin), adder);
- gst_bin_add(GST_BIN(main_bin), audiosink);
+ GST_INFO (0, "main: adding adder to bin");
+ gst_bin_add (GST_BIN(main_bin), adder);
+ GST_INFO (0, "main: adding audiosink to bin");
+ gst_bin_add (GST_BIN(main_bin), audiosink);
/* connect adder and audiosink */
gst_pad_connect(gst_element_get_pad(adder,"src"),
gst_element_get_pad(audiosink,"sink"));
- /* create input channels, add to bin and connect */
-
+ /* start looping */
input_channels = NULL;
for (i = 1; i < argc; ++i)
{
printf ("Opening channel %d from file %s...\n", i, argv[i]);
channel_in = create_input_channel (i, argv[i]);
- input_channels = g_list_append (input_channels, channel_in);
- gst_bin_add(GST_BIN(main_bin), channel_in->pipe);
+ input_channels = g_list_append (input_channels, channel_in);
+
+ if (i > 1) gst_element_set_state (main_bin, GST_STATE_PAUSED);
+ gst_bin_add (GST_BIN(main_bin), channel_in->pipe);
/* request pads and connect to adder */
+ GST_INFO (0, "requesting pad\n");
pad = gst_element_request_pad_by_name (adder, "sink%d");
- g_print ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
+ printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
sprintf (buffer, "channel%d", i);
gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad);
@@ -178,24 +181,32 @@ int main(int argc,char *argv[])
env_register_cp (channel_in->volenv, num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */
}
env_register_cp (channel_in->volenv, num_channels * 10.0 , 1.0 / num_channels); /* to end level */
- }
-
- /* sleep a few seconds doesn't seem to help anyway */
- printf ("Sleeping a few seconds ...\n");
- sleep (2);
- printf ("Waking up ...\n");
+ xmlSaveFile("mixer.xml", gst_xml_write(GST_ELEMENT(main_bin)));
-
- /* start playing */
- gst_element_set_state(main_bin, GST_STATE_PLAYING);
+ /* start playing */
+ gst_element_set_state(main_bin, GST_STATE_PLAYING);
- playing = TRUE;
+ // write out the schedule
+ gst_schedule_show(GST_ELEMENT_SCHED(main_bin));
+ playing = TRUE;
- while (playing) {
+ j = 0;
+ //printf ("main: start iterating from 0");
+ while (playing && j < 100)
+ {
+// printf ("main: iterating %d\n", j);
+ gst_bin_iterate(GST_BIN(main_bin));
+ //fprintf(stderr,"after iterate()\n");
+ ++j;
+ }
+ }
+ printf ("main: all the channels are open\n");
+ while (playing)
+ {
gst_bin_iterate(GST_BIN(main_bin));
+ //fprintf(stderr,"after iterate()\n");
}
-
/* stop the bin */
gst_element_set_state(main_bin, GST_STATE_NULL);
@@ -228,11 +239,10 @@ create_input_channel (int id, char* location)
GstAutoplug *autoplug;
GstCaps *srccaps;
GstElement *new_element;
+ GstElement *decoder;
-#ifdef DEBUG
- printf ("DEBUG : c_i_p : creating channel with id %d for file %s\n",
+ GST_DEBUG (0, "c_i_p : creating channel with id %d for file %s\n",
id, location);
-#endif
/* allocate channel */
@@ -245,23 +255,21 @@ create_input_channel (int id, char* location)
/* create channel */
-#ifdef DEBUG
- printf ("DEBUG : c_i_p : creating pipeline\n");
-#endif
+ GST_DEBUG (0, "c_i_p : creating pipeline\n");
- channel->pipe = gst_bin_new ("pipeline");
+ sprintf (buffer, "pipeline%d", id);
+ channel->pipe = gst_bin_new (buffer);
g_assert(channel->pipe != NULL);
/* create elements */
-#ifdef DEBUG
- printf ("DEBUG : c_i_p : creating disksrc\n");
-#endif
+ GST_DEBUG(0, "c_i_p : creating disksrc\n");
sprintf (buffer, "disksrc%d", id);
channel->disksrc = gst_elementfactory_make ("disksrc", buffer);
g_assert(channel->disksrc != NULL);
-
+
+ GST_DEBUG(0, "c_i_p : setting location\n");
gtk_object_set(GTK_OBJECT(channel->disksrc),"location", location, NULL);
/* add disksrc to the bin before autoplug */
@@ -286,8 +294,24 @@ create_input_channel (int id, char* location)
printf ("DEBUG : c_i_p : getting srccaps\n");
#endif
+#ifdef WITH_BUG
srccaps = gst_play_typefind (GST_BIN (channel->pipe), channel->disksrc);
+#endif
+#ifdef WITH_BUG2
+ {
+ GstElement *pipeline;
+ pipeline = gst_pipeline_new ("autoplug_pipeline");
+
+ gst_bin_add (GST_BIN (pipeline), channel->pipe);
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN (pipeline), channel->pipe);
+
+ }
+#endif
+
+#ifdef AUTOPLUG
if (!srccaps) {
g_print ("could not autoplug, unknown media type...\n");
exit (-1);
@@ -311,7 +335,24 @@ create_input_channel (int id, char* location)
g_print ("could not autoplug, no suitable codecs found...\n");
exit (-1);
}
+
+#else
+
+ new_element = gst_bin_new ("autoplug_bin");
+
+ /* static plug, use mad plugin and assume mp3 input */
+ decoder = gst_elementfactory_make ("mad", "mpg123");
+
+ gst_bin_add (GST_BIN (new_element), decoder);
+
+ gst_element_add_ghost_pad (new_element,
+ gst_element_get_pad (decoder, "sink"), "sink");
+ gst_element_add_ghost_pad (new_element,
+ gst_element_get_pad (decoder, "src"), "src_00");
+#endif
+ xmlSaveFile ("mixer.gst", gst_xml_write (new_element));
+
gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
gst_bin_add (GST_BIN (channel->pipe), new_element);
diff --git a/gst/Makefile.am b/gst/Makefile.am
index cfd5ac69a..edd8c0df7 100644
--- a/gst/Makefile.am
+++ b/gst/Makefile.am
@@ -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)
diff --git a/gst/autoplug/Makefile.am b/gst/autoplug/Makefile.am
index 8050727ae..043317a26 100644
--- a/gst/autoplug/Makefile.am
+++ b/gst/autoplug/Makefile.am
@@ -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
index 000000000..748175ffd
--- /dev/null
+++ b/gst/autoplug/autoplugtest.c
@@ -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
index 000000000..094867238
--- /dev/null
+++ b/gst/autoplug/gstautoplugcache.c
@@ -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
index 000000000..883d8cdc1
--- /dev/null
+++ b/gst/autoplug/gstautoplugger.c
@@ -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
+};
+
diff --git a/gst/autoplug/gststaticautoplug.c b/gst/autoplug/gststaticautoplug.c
index 11403a069..3edf83e78 100644
--- a/gst/autoplug/gststaticautoplug.c
+++ b/gst/autoplug/gststaticautoplug.c
@@ -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;
}
diff --git a/gst/autoplug/gststaticautoplugrender.c b/gst/autoplug/gststaticautoplugrender.c
index c544f7f18..cbfc798fa 100644
--- a/gst/autoplug/gststaticautoplugrender.c
+++ b/gst/autoplug/gststaticautoplugrender.c
@@ -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);
diff --git a/gst/cothreads.c b/gst/cothreads.c
index 2de2b3ee6..478dba0d3 100644
--- a/gst/cothreads.c
+++ b/gst/cothreads.c
@@ -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
+}
+
diff --git a/gst/cothreads.h b/gst/cothreads.h
index d48b1abbd..d95d7cf73 100644
--- a/gst/cothreads.h
+++ b/gst/cothreads.h
@@ -26,6 +26,12 @@
#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__ */
diff --git a/gst/elements/gstfakesrc.c b/gst/elements/gstfakesrc.c
index 5fa6af217..97570bbb8 100644
--- a/gst/elements/gstfakesrc.c
+++ b/gst/elements/gstfakesrc.c
@@ -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();
diff --git a/gst/elements/gstfakesrc.h b/gst/elements/gstfakesrc.h
index a795c1932..ba92f631b 100644
--- a/gst/elements/gstfakesrc.h
+++ b/gst/elements/gstfakesrc.h
@@ -65,6 +65,7 @@ struct _GstFakeSrc {
GstElement element;
gboolean loop_based;
+ gboolean eos;
gint numsrcpads;
GSList *srcpads;
GstFakeSrcOutputType output;
diff --git a/gst/elements/gstsinesrc.c b/gst/elements/gstsinesrc.c
index 8cddd5d7b..6a00e1eef 100644
--- a/gst/elements/gstsinesrc.c
+++ b/gst/elements/gstsinesrc.c
@@ -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
+}
diff --git a/gst/gst.c b/gst/gst.c
index be7eeb4fa..e859b0439 100644
--- 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;
diff --git a/gst/gst.h b/gst/gst.h
index 94a1444f2..73bdb0b84 100644
--- 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>
diff --git a/gst/gstbin.c b/gst/gstbin.c
index dc0331e07..a45f13489 100644
--- a/gst/gstbin.c
+++ b/gst/gstbin.c
@@ -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;
}
diff --git a/gst/gstbin.h b/gst/gstbin.h
index 23b826fc6..da5d8aa83 100644
--- a/gst/gstbin.h
+++ b/gst/gstbin.h
@@ -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);
diff --git a/gst/gstbuffer.c b/gst/gstbuffer.c
index 23f68e73a..7a44084ca 100644
--- a/gst/gstbuffer.c
+++ b/gst/gstbuffer.c
@@ -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
diff --git a/gst/gstcaps.c b/gst/gstcaps.c
index df122b58b..0ef1c5543 100644
--- a/gst/gstcaps.c
+++ b/gst/gstcaps.c
@@ -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;
}
}
diff --git a/gst/gstclock.c b/gst/gstclock.c
index 8040baf33..0c3caad5b 100644
--- a/gst/gstclock.c
+++ b/gst/gstclock.c
@@ -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);
}
diff --git a/gst/gstelement.c b/gst/gstelement.c
index 7241b406c..37e5e0318 100644
--- a/gst/gstelement.c
+++ b/gst/gstelement.c
@@ -26,14 +26,16 @@
#include "gstelement.h"
#include "gstextratypes.h"
#include "gstbin.h"
+#include "gstscheduler.h"
#include "gstutils.h"
-
/* Element signals and args */
enum {
STATE_CHANGE,
NEW_PAD,
+ PAD_REMOVED,
NEW_GHOST_PAD,
+ GHOST_PAD_REMOVED,
ERROR,
EOS,
LAST_SIGNAL
@@ -48,6 +50,10 @@ enum {
static void gst_element_class_init (GstElementClass *klass);
static void gst_element_init (GstElement *element);
+static void gst_element_set_arg (GtkObject *object, GtkArg *arg, guint id);
+static void gst_element_get_arg (GtkObject *object, GtkArg *arg, guint id);
+
+static void gst_element_shutdown (GtkObject *object);
static void gst_element_real_destroy (GtkObject *object);
static GstElementStateReturn gst_element_change_state (GstElement *element);
@@ -67,8 +73,8 @@ GtkType gst_element_get_type(void) {
sizeof(GstElementClass),
(GtkClassInitFunc)gst_element_class_init,
(GtkObjectInitFunc)gst_element_init,
- (GtkArgSetFunc)NULL,
- (GtkArgGetFunc)NULL,
+ (GtkArgSetFunc)gst_element_set_arg,
+ (GtkArgGetFunc)gst_element_get_arg,
(GtkClassInitFunc)NULL,
};
element_type = gtk_type_unique(GST_TYPE_OBJECT,&element_info);
@@ -97,11 +103,21 @@ gst_element_class_init (GstElementClass *klass)
GTK_SIGNAL_OFFSET (GstElementClass, new_pad),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GST_TYPE_PAD);
+ gst_element_signals[PAD_REMOVED] =
+ gtk_signal_new ("pad_removed", GTK_RUN_LAST, gtkobject_class->type,
+ GTK_SIGNAL_OFFSET (GstElementClass, pad_removed),
+ gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
+ GST_TYPE_PAD);
gst_element_signals[NEW_GHOST_PAD] =
gtk_signal_new ("new_ghost_pad", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstElementClass, new_ghost_pad),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GST_TYPE_PAD);
+ gst_element_signals[GHOST_PAD_REMOVED] =
+ gtk_signal_new ("ghost_pad_removed", GTK_RUN_LAST, gtkobject_class->type,
+ GTK_SIGNAL_OFFSET (GstElementClass, ghost_pad_removed),
+ gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
+ GST_TYPE_PAD);
gst_element_signals[ERROR] =
gtk_signal_new ("error", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstElementClass, error),
@@ -115,11 +131,15 @@ gst_element_class_init (GstElementClass *klass)
gtk_object_class_add_signals (gtkobject_class, gst_element_signals, LAST_SIGNAL);
- gtkobject_class->destroy = gst_element_real_destroy;
+ gtkobject_class->set_arg = GST_DEBUG_FUNCPTR(gst_element_set_arg);
+ gtkobject_class->get_arg = GST_DEBUG_FUNCPTR(gst_element_get_arg);
+ gtkobject_class->shutdown = GST_DEBUG_FUNCPTR(gst_element_shutdown);
+ gtkobject_class->destroy = GST_DEBUG_FUNCPTR(gst_element_real_destroy);
- gstobject_class->save_thyself = gst_element_save_thyself;
+ gstobject_class->save_thyself = GST_DEBUG_FUNCPTR(gst_element_save_thyself);
+ gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR(gst_element_restore_thyself);
- klass->change_state = gst_element_change_state;
+ klass->change_state = GST_DEBUG_FUNCPTR(gst_element_change_state);
klass->elementfactory = NULL;
}
@@ -134,8 +154,38 @@ gst_element_init (GstElement *element)
element->pads = NULL;
element->loopfunc = NULL;
element->threadstate = NULL;
+ element->sched = NULL;
}
+
+static void
+gst_element_set_arg (GtkObject *object, GtkArg *arg, guint id)
+{
+ GstElementClass *oclass = GST_ELEMENT_CLASS (object->klass);
+
+ GST_SCHEDULE_LOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
+
+ if (oclass->set_arg)
+ (oclass->set_arg)(object,arg,id);
+
+ GST_SCHEDULE_UNLOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
+}
+
+
+static void
+gst_element_get_arg (GtkObject *object, GtkArg *arg, guint id)
+{
+ GstElementClass *oclass = GST_ELEMENT_CLASS (object->klass);
+
+ GST_SCHEDULE_LOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
+
+ if (oclass->get_arg)
+ (oclass->get_arg)(object,arg,id);
+
+ GST_SCHEDULE_UNLOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
+}
+
+
/**
* gst_element_new:
*
@@ -237,9 +287,15 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
+ // first check to make sure the pad's parent is already set
+ g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
+
+ // then check to see if there's already a pad by that name here
+ g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
+
/* set the pad's parent */
- GST_DEBUG (0,"setting parent of pad '%s'(%p) to '%s'(%p)\n",
- GST_PAD_NAME (pad), pad, GST_ELEMENT_NAME (element), element);
+ GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'\n",
+ GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
/* add it to the list */
@@ -255,6 +311,36 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
}
/**
+ * gst_element_remove_pad:
+ * @element: element to remove pad from
+ * @pad: pad to remove
+ *
+ * Remove a pad (connection point) from the element,
+ */
+void
+gst_element_remove_pad (GstElement *element, GstPad *pad)
+{
+ g_return_if_fail (element != NULL);
+ g_return_if_fail (GST_IS_ELEMENT (element));
+ g_return_if_fail (pad != NULL);
+ g_return_if_fail (GST_IS_PAD (pad));
+
+ g_return_if_fail (GST_PAD_PARENT (pad) == element);
+
+ /* add it to the list */
+ element->pads = g_list_remove (element->pads, pad);
+ element->numpads--;
+ if (gst_pad_get_direction (pad) == GST_PAD_SRC)
+ element->numsrcpads--;
+ else
+ element->numsinkpads--;
+
+ gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[PAD_REMOVED], pad);
+
+ gst_object_unparent (GST_OBJECT (pad));
+}
+
+/**
* gst_element_add_ghost_pad:
* @element: element to add ghost pad to
* @pad: pad from which the new ghost pad will be created
@@ -273,17 +359,22 @@ gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name)
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
- GST_DEBUG(0,"creating new ghost pad called %s, from pad %s:%s\n",name,GST_DEBUG_PAD_NAME(pad));
+ // then check to see if there's already a pad by that name here
+ g_return_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE);
+
+ GST_DEBUG(GST_CAT_ELEMENT_PADS,"creating new ghost pad called %s, from pad %s:%s\n",
+ name,GST_DEBUG_PAD_NAME(pad));
ghostpad = gst_ghost_pad_new (name, pad);
/* add it to the list */
- GST_DEBUG(0,"adding ghost pad %s to element %s\n", name, GST_ELEMENT_NAME (element));
+ GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s\n",
+ name, GST_ELEMENT_NAME (element));
element->pads = g_list_append (element->pads, ghostpad);
element->numpads++;
// set the parent of the ghostpad
gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
- GST_DEBUG(0,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
+ GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
/* emit the NEW_GHOST_PAD signal */
gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_GHOST_PAD], ghostpad);
@@ -331,21 +422,18 @@ gst_element_get_pad (GstElement *element, const gchar *name)
if (!element->numpads)
return NULL;
- GST_DEBUG(GST_CAT_ELEMENT_PADS,"searching for pad '%s' in element %s\n",
- name, GST_ELEMENT_NAME (element));
-
// look through the list, matching by name
walk = element->pads;
while (walk) {
GstPad *pad = GST_PAD(walk->data);
- if (!strcmp (gst_object_get_name (GST_OBJECT(pad)), name)) {
- GST_DEBUG(GST_CAT_ELEMENT_PADS,"found pad '%s'\n",name);
+ if (!strcmp (GST_PAD_NAME(pad), name)) {
+ GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad));
return pad;
}
walk = g_list_next (walk);
}
- GST_DEBUG(GST_CAT_ELEMENT_PADS,"no such pad '%s'\n",name);
+ GST_INFO(GST_CAT_ELEMENT_PADS,"no such pad '%s' in element \"%s\"",name,GST_ELEMENT_NAME(element));
return NULL;
}
@@ -440,7 +528,7 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *
GstPadTemplate *newtempl = NULL;
GList *padlist;
- GST_DEBUG(0,"gst_element_get_padtemplate_by_compatible()\n");
+ GST_DEBUG(GST_CAT_ELEMENT_PADS,"gst_element_get_padtemplate_by_compatible()\n");
g_return_val_if_fail (element != NULL, NULL);
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
@@ -457,19 +545,19 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *
// Check direction (must be opposite)
// Check caps
- GST_DEBUG(0,"checking direction and caps\n");
+ GST_DEBUG(GST_CAT_CAPS,"checking direction and caps\n");
if (padtempl->direction == GST_PAD_SRC &&
compattempl->direction == GST_PAD_SINK) {
- GST_DEBUG(0,"compatible direction: found src pad template\n");
+ GST_DEBUG(GST_CAT_CAPS,"compatible direction: found src pad template\n");
compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (padtempl),
GST_PADTEMPLATE_CAPS (compattempl));
- GST_DEBUG(0,"caps are %scompatible\n", (compat?"":"not "));
+ GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
} else if (padtempl->direction == GST_PAD_SINK &&
compattempl->direction == GST_PAD_SRC) {
- GST_DEBUG(0,"compatible direction: found sink pad template\n");
+ GST_DEBUG(GST_CAT_CAPS,"compatible direction: found sink pad template\n");
compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (compattempl),
GST_PADTEMPLATE_CAPS (padtempl));
- GST_DEBUG(0,"caps are %scompatible\n", (compat?"":"not "));
+ GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
}
if (compat) {
@@ -659,7 +747,7 @@ gst_element_disconnect (GstElement *src, const gchar *srcpadname,
void
gst_element_error (GstElement *element, const gchar *error)
{
- g_error("GstElement: error in element '%s': %s\n", gst_object_get_name (GST_OBJECT (element)), error);
+ g_error("GstElement: error in element '%s': %s\n", GST_ELEMENT_NAME(element), error);
/* FIXME: this is not finished!!! */
@@ -689,6 +777,11 @@ gst_element_set_state (GstElement *element, GstElementState state)
g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
+ g_return_val_if_fail (element->sched != NULL, GST_STATE_FAILURE);
+
+ GST_DEBUG_ELEMENT (GST_CAT_STATES,element, "setting state from %s to %s\n",
+ gst_element_statename(GST_STATE(element)),
+ gst_element_statename(state));
/* start with the current state */
curpending = GST_STATE(element);
@@ -702,6 +795,9 @@ gst_element_set_state (GstElement *element, GstElementState state)
/* set the pending state variable */
// FIXME: should probably check to see that we don't already have one
GST_STATE_PENDING (element) = curpending;
+ if (curpending != state)
+ GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"intermediate: setting state to %s\n",
+ gst_element_statename(curpending));
/* call the state change function so it can set the state */
oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
@@ -711,7 +807,7 @@ gst_element_set_state (GstElement *element, GstElementState state)
/* if that outright didn't work, we need to bail right away */
/* NOTE: this will bail on ASYNC as well! */
if (return_val == GST_STATE_FAILURE) {
-// GST_DEBUG (0,"have async return from '%s'\n",GST_ELEMENT_NAME (element));
+ GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"have failed change_state return\n");
return return_val;
}
}
@@ -741,6 +837,7 @@ gst_element_get_factory (GstElement *element)
return oclass->elementfactory;
}
+
/**
* gst_element_change_state:
* @element: element to change state of
@@ -757,15 +854,48 @@ gst_element_change_state (GstElement *element)
g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
-// g_print("gst_element_change_state(\"%s\",%d)\n",
-// element->name,state);
+// GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "default handler sets state to %s\n",
+// gst_element_statename(GST_STATE_PENDING(element)));
+
+ if (GST_STATE_TRANSITION(element) == GST_STATE_PAUSED_TO_PLAYING) {
+ g_return_val_if_fail(GST_ELEMENT_SCHED(element), GST_STATE_FAILURE);
+ if (GST_ELEMENT_PARENT(element))
+ fprintf(stderr,"PAUSED->PLAYING: element \"%s\" has parent \"%s\" and sched %p\n",
+GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
+ GST_SCHEDULE_ENABLE_ELEMENT (element->sched,element);
+ }
+ else if (GST_STATE_TRANSITION(element) == GST_STATE_PLAYING_TO_PAUSED) {
+ if (GST_ELEMENT_PARENT(element))
+ fprintf(stderr,"PLAYING->PAUSED: element \"%s\" has parent \"%s\" and sched %p\n",
+GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
+ GST_SCHEDULE_DISABLE_ELEMENT (element->sched,element);
+ }
GST_STATE (element) = GST_STATE_PENDING (element);
GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING;
+ // note: queues' state_change is a special case because it needs to lock
+ // for synchronization (from another thread). since this signal may block
+ // or (worse) make another state change, the queue needs to unlock before
+ // calling. thus, gstqueue.c::gst_queue_state_change() blocks, unblocks,
+ // unlocks, then emits this.
gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[STATE_CHANGE],
GST_STATE (element));
- return TRUE;
+ return GST_STATE_SUCCESS;
+}
+
+static void
+gst_element_shutdown (GtkObject *object)
+{
+ GstElement *element = GST_ELEMENT (object);
+
+ GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "shutdown\n");
+
+ if (GST_IS_BIN (GST_OBJECT_PARENT (element)))
+ gst_bin_remove (GST_BIN (GST_OBJECT_PARENT (element)), element);
+
+ if (GTK_OBJECT_CLASS (parent_class)->shutdown)
+ GTK_OBJECT_CLASS (parent_class)->shutdown (object);
}
static void
@@ -775,16 +905,29 @@ gst_element_real_destroy (GtkObject *object)
GList *pads;
GstPad *pad;
-// g_print("in gst_element_real_destroy()\n");
-
- pads = element->pads;
- while (pads) {
- pad = GST_PAD (pads->data);
- gst_pad_destroy (pad);
- pads = g_list_next (pads);
+ GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "destroy\n");
+
+ if (element->pads) {
+ GList *orig;
+ orig = pads = g_list_copy (element->pads);
+ while (pads) {
+ pad = GST_PAD (pads->data);
+ //gst_object_destroy (GST_OBJECT (pad));
+ gst_object_ref (GST_OBJECT (pad));
+ gst_element_remove_pad (element, pad);
+ gst_object_unref (GST_OBJECT (pad));
+ pads = g_list_next (pads);
+ }
+ g_list_free (orig);
+ g_list_free (element->pads);
+ element->pads = NULL;
}
- g_list_free (element->pads);
+ element->numsrcpads = 0;
+ element->numsinkpads = 0;
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
/*
@@ -830,7 +973,7 @@ gst_element_save_thyself (GstObject *object,
oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
- xmlNewChild(parent, NULL, "name", gst_object_get_name (GST_OBJECT (element)));
+ xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
if (oclass->elementfactory != NULL) {
GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
@@ -839,6 +982,9 @@ gst_element_save_thyself (GstObject *object,
xmlNewChild (parent, NULL, "version", factory->details->version);
}
+// if (element->manager)
+// xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager));
+
// output all args to the element
type = GTK_OBJECT_TYPE (element);
while (type != GTK_TYPE_INVALID) {
@@ -918,7 +1064,7 @@ gst_element_save_thyself (GstObject *object,
}
/**
- * gst_element_load_thyself:
+ * gst_element_restore_thyself:
* @self: the xml node
* @parent: the parent of this object when it's loaded
*
@@ -927,7 +1073,7 @@ gst_element_save_thyself (GstObject *object,
* Returns: the new element
*/
GstElement*
-gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
+gst_element_restore_thyself (xmlNodePtr self, GstObject *parent)
{
xmlNodePtr children = self->xmlChildrenNode;
GstElement *element;
@@ -948,7 +1094,7 @@ gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (type != NULL, NULL);
- GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"\n", name, type);
+ GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"", name, type);
element = gst_elementfactory_make (type, name);
@@ -1002,32 +1148,33 @@ gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
}
/**
- * gst_element_set_manager:
+ * gst_element_set_sched:
* @element: Element to set manager of.
- * @manager: Element to be the manager.
+ * @sched: @GstSchedule to set.
*
- * Sets the manager of the element. For internal use only, unless you're
+ * Sets the scheduler of the element. For internal use only, unless you're
* writing a new bin subclass.
*/
void
-gst_element_set_manager (GstElement *element,
- GstElement *manager)
+gst_element_set_sched (GstElement *element,
+ GstSchedule *sched)
{
- element->manager = manager;
+ GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p",sched);
+ element->sched = sched;
}
/**
- * gst_element_get_manager:
+ * gst_element_get_sched:
* @element: Element to get manager of.
*
- * Returns the manager of the element.
+ * Returns the scheduler of the element.
*
- * Returns: Element's manager
+ * Returns: Element's scheduler
*/
-GstElement*
-gst_element_get_manager (GstElement *element)
+GstSchedule*
+gst_element_get_sched (GstElement *element)
{
- return element->manager;
+ return element->sched;
}
/**
@@ -1070,3 +1217,24 @@ gst_element_signal_eos (GstElement *element)
GST_FLAG_SET(element,GST_ELEMENT_COTHREAD_STOPPING);
}
+
+const gchar *gst_element_statename(int state) {
+ switch (state) {
+#ifdef GST_DEBUG_COLOR
+ case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
+ case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
+ case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
+ case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
+ case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
+ default: return "\033[01;37;41mUNKNOWN!\033[00m";
+#else
+ case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
+ case GST_STATE_NULL: return "NULL";break;
+ case GST_STATE_READY: return "READY";break;
+ case GST_STATE_PLAYING: return "PLAYING";break;
+ case GST_STATE_PAUSED: return "PAUSED";break;
+ default: return "UNKNOWN!";
+#endif
+ }
+ return "";
+}
diff --git a/gst/gstelement.h b/gst/gstelement.h
index cc296c941..212dd4cdc 100644
--- a/gst/gstelement.h
+++ b/gst/gstelement.h
@@ -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 */
diff --git a/gst/gstelementfactory.c b/gst/gstelementfactory.c
index 997cb2055..9c4bc42e7 100644
--- a/gst/gstelementfactory.c
+++ b/gst/gstelementfactory.c
@@ -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);
diff --git a/gst/gstinfo.c b/gst/gstinfo.c
index 15263722c..46ccbde76 100644
--- a/gst/gstinfo.c
+++ b/gst/gstinfo.c
@@ -20,6 +20,7 @@
* Boston, MA 02111-1307, USA.
*/
+#include <dlfcn.h>
#include "gst_private.h"
#include "gstelement.h"
#include "gstpad.h"
@@ -27,19 +28,7 @@
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;
+}
diff --git a/gst/gstinfo.h b/gst/gstinfo.h
index 620d809dd..71fdba9f4 100644
--- a/gst/gstinfo.h
+++ b/gst/gstinfo.h
@@ -34,6 +34,14 @@
#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__ */
diff --git a/gst/gstobject.c b/gst/gstobject.c
index 2e7eafb88..82c7e2b0f 100644
--- a/gst/gstobject.c
+++ b/gst/gstobject.c
@@ -53,6 +53,10 @@ static guint gst_signal_object_signals[SO_LAST_SIGNAL] = { 0 };
static void gst_object_class_init (GstObjectClass *klass);
static void gst_object_init (GstObject *object);
+static void gst_object_real_destroy (GtkObject *gtk_object);
+static void gst_object_shutdown (GtkObject *gtk_object);
+static void gst_object_finalize (GtkObject *gtk_object);
+
static GtkObjectClass *parent_class = NULL;
static guint gst_object_signals[LAST_SIGNAL] = { 0 };
@@ -105,6 +109,10 @@ gst_object_class_init (GstObjectClass *klass)
klass->path_string_separator = "/";
klass->signal_object = gtk_type_new (gst_signal_object_get_type ());
+
+ gtkobject_class->shutdown = gst_object_shutdown;
+ gtkobject_class->destroy = gst_object_real_destroy;
+ gtkobject_class->finalize = gst_object_finalize;
}
static void
@@ -118,9 +126,12 @@ gst_object_init (GstObject *object)
#ifdef HAVE_ATOMIC_H
atomic_set(&(object->refcount),1);
#else
- object->refcount++;
+ object->refcount = 1;
#endif
object->parent = NULL;
+
+ object->flags = 0;
+ GST_FLAG_SET (object, GST_FLOATING);
}
/**
@@ -137,6 +148,122 @@ gst_object_new (void)
}
/**
+ * gst_object_ref:
+ * @object: GstObject to reference
+ *
+ * Increments the refence count on the object.
+ */
+GstObject*
+gst_object_ref (GstObject *object)
+{
+ g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
+
+ GST_DEBUG (GST_CAT_REFCOUNTING, "ref '%s' %d->%d\n",GST_OBJECT_NAME(object),
+ GTK_OBJECT(object)->ref_count,GTK_OBJECT(object)->ref_count+1);
+
+ gtk_object_ref (GTK_OBJECT (object));
+
+ return object;
+}
+#define gst_object_ref gst_object_ref
+
+/**
+ * gst_object_unref:
+ * @object: GstObject to unreference
+ *
+ * Decrements the refence count on the object. If reference count hits
+ * zero, destroy the object.
+ */
+void
+gst_object_unref (GstObject *object)
+{
+ g_return_if_fail (GST_IS_OBJECT (object));
+
+ GST_DEBUG (GST_CAT_REFCOUNTING, "unref '%s' %d->%d\n",GST_OBJECT_NAME(object),
+ GTK_OBJECT(object)->ref_count,GTK_OBJECT(object)->ref_count-1);
+
+ gtk_object_unref (GTK_OBJECT (object));
+}
+#define gst_object_unref gst_object_unref
+
+/**
+ * gst_object_sink:
+ * @object: GstObject to sink
+ *
+ * Removes floating reference on an object. Any newly created object has
+ * a refcount of 1 and is FLOATING. This function should be used when
+ * creating a new object to symbolically 'take ownership of' the object.
+ */
+void
+gst_object_sink (GstObject *object)
+{
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GST_IS_OBJECT (object));
+
+ GST_DEBUG (GST_CAT_REFCOUNTING, "sink '%s'\n",GST_OBJECT_NAME(object));
+ if (GST_OBJECT_FLOATING (object))
+ {
+ GST_FLAG_UNSET (object, GST_FLOATING);
+ gst_object_unref (object);
+ }
+}
+
+void
+gst_object_destroy (GstObject *object)
+{
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GST_IS_OBJECT (object));
+
+ GST_DEBUG (GST_CAT_REFCOUNTING, "destroy '%s'\n",GST_OBJECT_NAME(object));
+ if (!GST_OBJECT_DESTROYED (object))
+ {
+ /* need to hold a reference count around all class method
+ * invocations.
+ */
+ gst_object_ref (object);
+ GTK_OBJECT (object)->klass->shutdown (GTK_OBJECT (object));
+ gst_object_unref (object);
+ }
+}
+
+static void
+gst_object_shutdown (GtkObject *object)
+{
+ GST_DEBUG (GST_CAT_REFCOUNTING, "shutdown '%s'\n",GST_OBJECT_NAME(object));
+ GST_FLAG_SET (GST_OBJECT (object), GST_DESTROYED);
+ parent_class->shutdown (GTK_OBJECT (object));
+}
+
+/* finilize is called when the object has to free its resources */
+static void
+gst_object_real_destroy (GtkObject *gtk_object)
+{
+ GST_DEBUG (GST_CAT_REFCOUNTING, "destroy '%s'\n",GST_OBJECT_NAME(gtk_object));
+
+ GST_OBJECT_PARENT (gtk_object) = NULL;
+
+ parent_class->destroy (gtk_object);
+}
+
+/* finilize is called when the object has to free its resources */
+static void
+gst_object_finalize (GtkObject *gtk_object)
+{
+ GstObject *object;
+
+ object = GST_OBJECT (gtk_object);
+
+ GST_DEBUG (GST_CAT_REFCOUNTING, "finalize '%s'\n",GST_OBJECT_NAME(object));
+
+ if (object->name != NULL)
+ g_free (object->name);
+
+ g_mutex_free (object->lock);
+
+ parent_class->finalize (gtk_object);
+}
+
+/**
* gst_object_set_name:
* @object: GstObject to set the name of
* @name: new name of object
@@ -315,26 +442,31 @@ gst_object_unref (GstObject *object)
#endif /* gst_object_unref */
/**
- * gst_object_sink:
- * @object: GstObject to sink
+ * gst_object_check_uniqueness:
+ * @list: a list of #GstObject to check through
+ * @name: the name to search for
*
- * Removes floating reference on an object. Any newly created object has
- * a refcount of 1 and is FLOATING. This function should be used when
- * creating a new object to symbolically 'take ownership of' the object.
+ * This function checks through the list of objects to see if the name
+ * given appears in the list as the name of an object. It returns TRUE if
+ * the name does not exist in the list.
+ *
+ * Returns: TRUE if the name doesn't appear in the list, FALSE if it does.
*/
-#ifndef gst_object_sink
-void
-gst_object_sink (GstObject *object)
+gboolean
+gst_object_check_uniqueness (GList *list, const gchar *name)
{
- g_return_if_fail (object != NULL);
- g_return_if_fail (GST_IS_OBJECT (object));
+ GstObject *child;
- if (GTK_OBJECT_FLOATING (object)) {
- GTK_OBJECT_UNSET_FLAGS (object, GTK_FLOATING);
- gst_object_unref (object);
+ while (list) {
+ child = GST_OBJECT (list->data);
+ list = g_list_next(list);
+
+ if (strcmp(GST_OBJECT_NAME(child), name) == 0) return FALSE;
}
+
+ return TRUE;
}
-#endif /* gst_object_sink */
+
/**
* gst_object_save_thyself:
@@ -528,6 +660,3 @@ gst_class_signal_emit_by_name (GstObject *object,
gtk_signal_emit_by_name (oclass->signal_object, name, object, self);
}
-
-
-
diff --git a/gst/gstobject.h b/gst/gstobject.h
index 9e1e6bb95..f7e095f61 100644
--- a/gst/gstobject.h
+++ b/gst/gstobject.h
@@ -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);
diff --git a/gst/gstpad.c b/gst/gstpad.c
index 48bd1e376..69913d25c 100644
--- a/gst/gstpad.c
+++ b/gst/gstpad.c
@@ -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);
}
diff --git a/gst/gstpad.h b/gst/gstpad.h
index 14731e0f2..c5d722452 100644
--- a/gst/gstpad.h
+++ b/gst/gstpad.h
@@ -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 */
diff --git a/gst/gstpipeline.c b/gst/gstpipeline.c
index f2772d488..f967add7c 100644
--- a/gst/gstpipeline.c
+++ b/gst/gstpipeline.c
@@ -24,6 +24,11 @@
#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
diff --git a/gst/gstprops.c b/gst/gstprops.c
index 25d5a24cd..380b53119 100644
--- a/gst/gstprops.c
+++ b/gst/gstprops.c
@@ -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:
diff --git a/gst/gstqueue.c b/gst/gstqueue.c
index 37a4f7f3c..755c8f8c2 100644
--- a/gst/gstqueue.c
+++ b/gst/gstqueue.c
@@ -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;
diff --git a/gst/gstqueue.h b/gst/gstqueue.h
index 606346735..085d5ac12 100644
--- a/gst/gstqueue.h
+++ b/gst/gstqueue.h
@@ -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);
diff --git a/gst/gstscheduler.c b/gst/gstscheduler.c
index e4e1d79b6..0795c18cd 100644
--- a/gst/gstscheduler.c
+++ b/gst/gstscheduler.c
@@ -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");
+ }
+}
diff --git a/gst/gstscheduler.h b/gst/gstscheduler.h
index 5cfbfff80..cdc905221 100644
--- a/gst/gstscheduler.h
+++ b/gst/gstscheduler.h
@@ -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
}
diff --git a/gst/gstthread.c b/gst/gstthread.c
index 1bdea99d0..8f91ff32d 100644
--- a/gst/gstthread.c
+++ b/gst/gstthread.c
@@ -26,7 +26,8 @@
#include "gst_private.h"
#include "gstthread.h"
-
+#include "gstscheduler.h"
+#include "gstqueue.h"
GstElementDetails gst_thread_details = {
"Threaded container",
@@ -45,14 +46,23 @@ enum {
};
enum {
+ SPINUP=0,
+ STATECHANGE,
+ STARTUP
+};
+
+enum {
ARG_0,
ARG_CREATE_THREAD,
};
+
static void gst_thread_class_init (GstThreadClass *klass);
static void gst_thread_init (GstThread *thread);
+static void gst_thread_real_destroy (GtkObject *gtk_object);
+
static void gst_thread_set_arg (GtkObject *object, GtkArg *arg, guint id);
static void gst_thread_get_arg (GtkObject *object, GtkArg *arg, guint id);
@@ -61,9 +71,7 @@ static GstElementStateReturn gst_thread_change_state (GstElement *element);
static xmlNodePtr gst_thread_save_thyself (GstObject *object, xmlNodePtr parent);
static void gst_thread_restore_thyself (GstObject *object, xmlNodePtr self);
-static void gst_thread_signal_thread (GstThread *thread);
-static void gst_thread_wait_thread (GstThread *thread);
-static void gst_thread_schedule_dummy (GstBin *bin);
+static void gst_thread_signal_thread (GstThread *thread, gboolean spinning);
static void* gst_thread_main_loop (void *arg);
@@ -108,12 +116,14 @@ gst_thread_class_init (GstThreadClass *klass)
gtk_object_add_arg_type ("GstThread::create_thread", GTK_TYPE_BOOL,
GTK_ARG_READWRITE, ARG_CREATE_THREAD);
+ gtkobject_class->destroy = gst_thread_real_destroy;
+
gstobject_class->save_thyself = gst_thread_save_thyself;
gstobject_class->restore_thyself = gst_thread_restore_thyself;
gstelement_class->change_state = gst_thread_change_state;
- gstbin_class->schedule = gst_thread_schedule_dummy;
+// gstbin_class->schedule = gst_thread_schedule_dummy;
gtkobject_class->set_arg = gst_thread_set_arg;
gtkobject_class->get_arg = gst_thread_get_arg;
@@ -123,26 +133,41 @@ gst_thread_class_init (GstThreadClass *klass)
static void
gst_thread_init (GstThread *thread)
{
- GST_DEBUG (0,"initializing thread '%s'\n",GST_ELEMENT_NAME (thread));
+
+ GST_DEBUG (GST_CAT_THREAD,"initializing thread\n");
// we're a manager by default
GST_FLAG_SET (thread, GST_BIN_FLAG_MANAGER);
// default is to create a thread
GST_FLAG_SET (thread, GST_THREAD_CREATE);
- GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
thread->lock = g_mutex_new();
thread->cond = g_cond_new();
+
+ GST_ELEMENT_SCHED(thread) = gst_schedule_new(GST_ELEMENT(thread));
+ GST_DEBUG(GST_CAT_THREAD, "thread's scheduler is %p\n",GST_ELEMENT_SCHED(thread));
+
+ thread->ppid = getpid();
+
+// gst_element_set_manager(GST_ELEMENT(thread),GST_ELEMENT(thread));
}
static void
-gst_thread_schedule_dummy (GstBin *bin)
+gst_thread_real_destroy (GtkObject *gtk_object)
{
- g_return_if_fail (GST_IS_THREAD (bin));
+ GstThread *thread = GST_THREAD (gtk_object);
+
+ GST_DEBUG (GST_CAT_REFCOUNTING,"destroy()\n");
+
+ g_mutex_free (thread->lock);
+ g_cond_free (thread->cond);
- if (!GST_FLAG_IS_SET (GST_THREAD (bin), GST_THREAD_STATE_SPINNING))
- GST_INFO (GST_CAT_THREAD,"gstthread: scheduling delayed until thread starts");
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ GTK_OBJECT_CLASS (parent_class)->destroy (gtk_object);
+
+ gst_object_destroy (GST_OBJECT (GST_ELEMENT_SCHED (thread)));
+ gst_object_unref (GST_OBJECT (GST_ELEMENT_SCHED (thread)));
}
static void
@@ -156,13 +181,13 @@ gst_thread_set_arg (GtkObject *object,
switch(id) {
case ARG_CREATE_THREAD:
if (GTK_VALUE_BOOL (*arg)) {
- GST_INFO (GST_CAT_THREAD,"gstthread: turning ON the creation of the thread");
+ GST_INFO (GST_CAT_THREAD,"turning ON the creation of the thread");
GST_FLAG_SET (object, GST_THREAD_CREATE);
- GST_DEBUG (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
+// GST_DEBUG (GST_CAT_THREAD,"flags are 0x%08x\n", GST_FLAGS (object));
} else {
GST_INFO (GST_CAT_THREAD,"gstthread: turning OFF the creation of the thread");
GST_FLAG_UNSET (object, GST_THREAD_CREATE);
- GST_DEBUG (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
+// GST_DEBUG (GST_CAT_THREAD,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
}
break;
default:
@@ -197,95 +222,237 @@ gst_thread_get_arg (GtkObject *object,
* Returns: The new thread
*/
GstElement*
-gst_thread_new (guchar *name)
+gst_thread_new (const guchar *name)
{
return gst_elementfactory_make ("thread", name);
}
+#define THR_INFO(format,args...) \
+ GST_INFO_ELEMENT(GST_CAT_THREAD, thread, "sync(" GST_DEBUG_THREAD_FORMAT "): " format , \
+ GST_DEBUG_THREAD_ARGS(thread->pid) , ## args )
+#define THR_DEBUG(format,args...) \
+ GST_DEBUG_ELEMENT(GST_CAT_THREAD, thread, "sync(" GST_DEBUG_THREAD_FORMAT "): " format , \
+ GST_DEBUG_THREAD_ARGS(thread->pid) , ## args )
+
+#define THR_INFO_MAIN(format,args...) \
+ GST_INFO_ELEMENT(GST_CAT_THREAD, thread, "sync-main(" GST_DEBUG_THREAD_FORMAT "): " format , \
+ GST_DEBUG_THREAD_ARGS(thread->ppid) , ## args )
+#define THR_DEBUG_MAIN(format,args...) \
+ GST_DEBUG_ELEMENT(GST_CAT_THREAD, thread, "sync-main(" GST_DEBUG_THREAD_FORMAT "): " format , \
+ GST_DEBUG_THREAD_ARGS(thread->ppid) , ## args )
+
static GstElementStateReturn
gst_thread_change_state (GstElement *element)
{
GstThread *thread;
gboolean stateset = GST_STATE_SUCCESS;
- gint pending, transition;
+ gint transition;
+ pthread_t self = pthread_self();
+ GstElement *peerelement;
g_return_val_if_fail (GST_IS_THREAD(element), FALSE);
- GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME(element));
+// GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME(element));
thread = GST_THREAD (element);
+// GST_DEBUG (GST_CAT_THREAD, "**** THREAD %ld changing THREAD %ld ****\n",self,thread->thread_id);
+// GST_DEBUG (GST_CAT_THREAD, "**** current pid=%d\n",getpid());
- GST_INFO (GST_CAT_THREAD,"gstthread: thread \"%s\" change state %d",
- GST_ELEMENT_NAME (GST_ELEMENT (element)),
- GST_STATE_PENDING (element));
-
- pending = GST_STATE_PENDING (element);
transition = GST_STATE_TRANSITION (element);
-// if (pending == GST_STATE (element)) return GST_STATE_SUCCESS;
+ THR_INFO("changing state from %s to %s",
+ gst_element_statename(GST_STATE (element)),
+ gst_element_statename(GST_STATE_PENDING (element)));
- GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
-
- if (GST_ELEMENT_CLASS (parent_class)->change_state)
- stateset = GST_ELEMENT_CLASS (parent_class)->change_state (element);
-
- GST_INFO (GST_CAT_THREAD, "gstthread: stateset %d %d %d %02x", GST_STATE (element), stateset,
- GST_STATE_PENDING (element), GST_STATE_TRANSITION (element));
+ //GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
switch (transition) {
case GST_STATE_NULL_TO_READY:
-// if (!stateset) return FALSE;
- // we want to prepare our internal state for doing the iterations
- GST_INFO (GST_CAT_THREAD, "gstthread: preparing thread \"%s\" for iterations:",
- GST_ELEMENT_NAME (GST_ELEMENT (element)));
-
// set the state to idle
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
- // create the thread if that's what we're supposed to do
- GST_INFO (GST_CAT_THREAD, "gstthread: flags are 0x%08x", GST_FLAGS (thread));
+ GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
+ // create the thread if that's what we're supposed to do
if (GST_FLAG_IS_SET (thread, GST_THREAD_CREATE)) {
- GST_INFO (GST_CAT_THREAD, "gstthread: starting thread \"%s\"",
- GST_ELEMENT_NAME (GST_ELEMENT (element)));
+ THR_DEBUG ("creating thread \"%s\"\n",
+ GST_ELEMENT_NAME (element));
g_mutex_lock (thread->lock);
+
// create the thread
pthread_create (&thread->thread_id, NULL,
gst_thread_main_loop, thread);
// wait for it to 'spin up'
- //gst_thread_wait_thread (thread);
- g_cond_wait (thread->cond, thread->lock);
- g_mutex_unlock (thread->lock);
+ THR_DEBUG("waiting for child thread spinup\n");
+ g_cond_wait(thread->cond,thread->lock);
+ THR_DEBUG("thread claims to be up\n");
+ g_mutex_unlock(thread->lock);
} else {
- GST_INFO (GST_CAT_THREAD, "gstthread: NOT starting thread \"%s\"",
+ GST_INFO (GST_CAT_THREAD, "NOT creating thread \"%s\"",
GST_ELEMENT_NAME (GST_ELEMENT (element)));
+
+ // punt and change state on all the children
+ if (GST_ELEMENT_CLASS (parent_class)->change_state)
+ stateset = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+ }
+ break;
+ case GST_STATE_READY_TO_PAUSED:
+ THR_INFO("readying thread");
+
+ // check to see if the thread is somehow changing its own state.
+ // FIXME this is currently illegal, but must somehow be made legal at some point.
+ if (pthread_equal(self, thread->thread_id))
+ {
+ //FIXME this should not happen
+ g_assert(!pthread_equal(self, thread->thread_id));
+ GST_FLAG_SET(thread, GST_THREAD_STATE_SPINNING);
+ GST_DEBUG(GST_CAT_THREAD,"no sync(" GST_DEBUG_THREAD_FORMAT "): setting own thread's state to spinning\n",
+ GST_DEBUG_THREAD_ARGS(thread->pid));
+ }
+ else
+ {
+ g_mutex_lock(thread->lock);
+ gst_thread_signal_thread(thread,FALSE);
}
break;
case GST_STATE_PAUSED_TO_PLAYING:
- case GST_STATE_READY_TO_PLAYING:
- if (!stateset) return FALSE;
- GST_INFO (GST_CAT_THREAD, "gstthread: starting thread \"%s\"",
- GST_ELEMENT_NAME (GST_ELEMENT (element)));
-
- GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
- gst_thread_signal_thread (thread);
+ THR_INFO("starting thread");
+
+ // check to see if the thread is somehow changing its own state.
+ // FIXME this is currently illegal, but must somehow be made legal at some point.
+ if (pthread_equal(self, thread->thread_id))
+ {
+ //FIXME this should not happen
+ g_assert(!pthread_equal(self, thread->thread_id));
+ GST_FLAG_SET(thread, GST_THREAD_STATE_SPINNING);
+ GST_DEBUG(GST_CAT_THREAD,"no sync(" GST_DEBUG_THREAD_FORMAT "): setting own thread's state to spinning\n",
+ GST_DEBUG_THREAD_ARGS(thread->pid));
+ }
+ else
+ {
+ THR_DEBUG("telling thread to start spinning\n");
+ g_mutex_lock(thread->lock);
+ gst_thread_signal_thread(thread,TRUE);
+ }
break;
case GST_STATE_PLAYING_TO_PAUSED:
- GST_INFO (GST_CAT_THREAD,"gstthread: pausing thread \"%s\"",
- GST_ELEMENT_NAME (GST_ELEMENT (element)));
-
- //GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
- gst_thread_signal_thread (thread);
+ THR_INFO("pausing thread");
+
+ // check to see if the thread is somehow changing its own state.
+ // FIXME this is currently illegal, but must somehow be made legal at some point.
+ if (pthread_equal(self, thread->thread_id))
+ {
+ //FIXME this should not happen
+ GST_DEBUG(GST_CAT_THREAD,"no sync(" GST_DEBUG_THREAD_FORMAT "): setting own thread's state to paused\n",
+ GST_DEBUG_THREAD_ARGS(thread->pid));
+ GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+ g_assert(!pthread_equal(self, thread->thread_id));
+ }
+ else
+ {
+ GList *elements = (element->sched)->elements;
+
+ // the following code ensures that the bottom half of thread will run
+ // to perform each elements' change_state() (by calling gstbin.c::
+ // change_state()).
+ // + the pending state was already set by gstelement.c::set_state()
+ // + find every queue we manage, and signal its empty and full conditions
+
+ g_mutex_lock(thread->lock);
+
+ GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+
+ while (elements)
+ {
+ GstElement *e = GST_ELEMENT(elements->data);
+ g_assert(e);
+ THR_DEBUG(" element \"%s\"\n",GST_ELEMENT_NAME(e));
+ elements = g_list_next(elements);
+ if (GST_IS_QUEUE(e))
+ {
+ //FIXME make this more efficient by only waking queues that are asleep
+ //FIXME and only waking the appropriate condition (depending on if it's
+ //FIXME on up- or down-stream side)
+ //
+ //FIXME also make this more efficient by keeping list of managed queues
+ THR_DEBUG("waking queue \"%s\"\n",GST_ELEMENT_NAME(e));
+ GST_LOCK(e);
+ g_cond_signal((GST_QUEUE(e)->emptycond));
+ g_cond_signal((GST_QUEUE(e)->fullcond));
+ GST_UNLOCK(e);
+ }
+ else
+ {
+ GList *pads = GST_ELEMENT_PADS(e);
+ while (pads)
+ {
+ GstPad *p = GST_PAD(pads->data);
+ pads = g_list_next(pads);
+
+ peerelement = GST_PAD_PARENT(GST_PAD_PEER(p));
+ if (!peerelement) continue; // deal with case where there's no peer
+
+ if (!GST_FLAG_IS_SET(peerelement,GST_ELEMENT_DECOUPLED)) {
+ GST_DEBUG(GST_CAT_THREAD,"peer element isn't DECOUPLED\n");
+ continue;
+ }
+
+ // FIXME this needs to go away eventually
+ if (!GST_IS_QUEUE(peerelement)) {
+ GST_DEBUG(GST_CAT_THREAD,"peer element isn't a Queue\n");
+ continue;
+ }
+
+ if (GST_ELEMENT_SCHED(peerelement) != GST_ELEMENT_SCHED(thread))
+ {
+ THR_DEBUG(" element \"%s\" has pad cross sched boundary\n",GST_ELEMENT_NAME(e));
+ GST_LOCK(peerelement);
+ g_cond_signal(GST_QUEUE(peerelement)->emptycond);
+ g_cond_signal(GST_QUEUE(peerelement)->fullcond);
+ GST_UNLOCK(peerelement);
+ }
+ }
+ }
+ }
+ THR_DEBUG("waiting for thread to stop spinning\n");
+ g_cond_wait (thread->cond, thread->lock);
+ THR_DEBUG("telling thread to pause\n");
+ gst_thread_signal_thread(thread,FALSE);
+ }
break;
case GST_STATE_READY_TO_NULL:
- GST_INFO (GST_CAT_THREAD,"gstthread: stopping thread \"%s\"",
- GST_ELEMENT_NAME (GST_ELEMENT (element)));
+ THR_INFO("stopping thread");
GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
- gst_thread_signal_thread (thread);
- pthread_join(thread->thread_id,NULL);
+
+ // check to see if the thread is somehow changing its own state.
+ // FIXME this is currently illegal, but must somehow be made legal at some point.
+ if (pthread_equal(self, thread->thread_id))
+ {
+ //FIXME this should not happen
+ g_assert(!pthread_equal(self, thread->thread_id));
+ THR_DEBUG("setting own thread's state to NULL (paused)\n");
+ GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+ }
+ else
+ {
+ THR_DEBUG("telling thread to pause (null) - and joining\n");
+ //MattH FIXME revisit
+// g_mutex_lock(thread->lock);
+// gst_thread_signal_thread(thread,FALSE);
+ pthread_join(thread->thread_id,NULL);
+ }
+
+ GST_FLAG_UNSET(thread,GST_THREAD_STATE_REAPING);
+ GST_FLAG_UNSET(thread,GST_THREAD_STATE_STARTED);
+ GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
+ GST_FLAG_UNSET(thread,GST_THREAD_STATE_ELEMENT_CHANGED);
+
+ if (GST_ELEMENT_CLASS (parent_class)->change_state)
+ stateset = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
+
break;
default:
break;
@@ -294,6 +461,16 @@ gst_thread_change_state (GstElement *element)
return stateset;
}
+static void gst_thread_update_state (GstThread *thread)
+{
+ // check for state change
+ if (GST_STATE_PENDING(thread) != GST_STATE_NONE_PENDING) {
+ // punt and change state on all the children
+ if (GST_ELEMENT_CLASS (parent_class)->change_state)
+ GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
+ }
+}
+
/**
* gst_thread_main_loop:
* @arg: the thread to start
@@ -305,53 +482,186 @@ static void *
gst_thread_main_loop (void *arg)
{
GstThread *thread = GST_THREAD (arg);
+ gint stateset;
+
+ thread->pid = getpid();
+ THR_INFO_MAIN("thread is running");
- GST_INFO (GST_CAT_THREAD,"gstthread: thread \"%s\" is running with PID %d",
- GST_ELEMENT_NAME (GST_ELEMENT (thread)), getpid ());
+ // first we need to change the state of all the children
+ if (GST_ELEMENT_CLASS (parent_class)->change_state)
+ stateset = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
// construct the plan and signal back
+/* DEPRACATED for INCSCHED1
+ THR_DEBUG_MAIN("creating plan for thread\n");
if (GST_BIN_CLASS (parent_class)->schedule)
GST_BIN_CLASS (parent_class)->schedule (GST_BIN (thread));
+*/
+
+// THR_DEBUG_MAIN("indicating spinup\n");
+ g_mutex_lock (thread->lock);
+ g_cond_signal (thread->cond);
+ // don't unlock the mutex because we hold it into the top of the while loop
+ THR_DEBUG_MAIN("thread has indicated spinup to parent process\n");
- gst_thread_signal_thread (thread);
+ /***** THREAD IS NOW IN READY STATE *****/
while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) {
- if (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
+ // NOTE we hold the thread lock at this point
+ // what we do depends on what state we're in
+ switch (GST_STATE(thread)) {
+ // NOTE: cannot be in NULL, we're not running in that state at all
+ case GST_STATE_READY:
+ // wait to be set to either the NULL or PAUSED states
+ THR_DEBUG_MAIN("thread in %s state, waiting for either %s or %s\n",
+ gst_element_statename(GST_STATE_READY),
+ gst_element_statename(GST_STATE_NULL),
+ gst_element_statename(GST_STATE_PAUSED));
+ g_cond_wait(thread->cond,thread->lock);
+ // been signaled, we need to state transition now and signal back
+ gst_thread_update_state(thread);
+ THR_DEBUG_MAIN("done with state transition, signaling back to parent process\n");
+ g_cond_signal(thread->cond);
+// g_mutex_unlock(thread->lock);
+ // now we decide what to do next (FIXME can be collapsed to a continue)
+ if (GST_STATE(thread) == GST_STATE_NULL) {
+ // REAPING must be set, we can simply break this iteration
+ continue;
+ } else {
+ // PAUSED is the next state, we can wait for that next
+ continue;
+ }
+ break;
+ case GST_STATE_PAUSED:
+ // wait to be set to either the READY or PLAYING states
+ THR_DEBUG_MAIN("thread in %s state, waiting for either %s or %s\n",
+ gst_element_statename(GST_STATE_PAUSED),
+ gst_element_statename(GST_STATE_READY),
+ gst_element_statename(GST_STATE_PLAYING));
+ g_cond_wait(thread->cond,thread->lock);
+ // been signaled, we need to state transition now and signal back
+ gst_thread_update_state(thread);
+ g_cond_signal(thread->cond);
+// g_mutex_unlock(thread->lock);
+ // now we decide what to do next
+ if (GST_STATE(thread) == GST_STATE_READY) {
+ // READY is the next state, we can wait for that next
+ continue;
+ } else {
+ g_mutex_unlock(thread->lock);
+ // PLAYING is coming up, so we can now start spinning
+ while (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
+ if (!gst_bin_iterate (GST_BIN (thread))) {
+ GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+ THR_DEBUG_MAIN("removed spinning state due to failed iteration!\n");
+ }
+ }
+ g_mutex_lock(thread->lock);
+ // once we're here, SPINNING has stopped, we should signal that we're done
+ THR_DEBUG_MAIN("SPINNING stopped, signaling back to parent process\n");
+ g_cond_signal (thread->cond);
+ // now we can wait for PAUSED
+ continue;
+ }
+ break;
+ case GST_STATE_PLAYING:
+ // wait to be set to PAUSED
+ THR_DEBUG_MAIN("thread in %s state, waiting for %s\n",
+ gst_element_statename(GST_STATE_PLAYING),
+ gst_element_statename(GST_STATE_PAUSED));
+ g_cond_wait(thread->cond,thread->lock);
+ // been signaled, we need to state transition now and signal back
+ gst_thread_update_state(thread);
+ g_cond_signal(thread->cond);
+// g_mutex_unlock(thread->lock);
+ // now we decide what to do next
+ // there's only PAUSED, we we just wait for it
+ continue;
+ break;
+ }
+
+ // need to grab the lock so we're ready for the top of the loop
+// g_mutex_lock(thread->lock);
+ }
+
+/*
+ while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) {
+ // start out by waiting for a state change into spinning
+ THR_DEBUG_MAIN("waiting for signal from parent process (at top of while())\n");
+ g_cond_wait (thread->cond,thread->lock);
+ THR_DEBUG_MAIN("woken up with %s pending\n",gst_element_statename(GST_STATE(thread)));
+ // now is a good time to change the state of the children and the thread itself
+ gst_thread_update_state (thread);
+ THR_DEBUG_MAIN("done changing state, signaling back\n");
+ g_cond_signal (thread->cond);
+ g_mutex_unlock (thread->lock);
+ THR_DEBUG_MAIN("finished sycnronizing with main process\n");
+
+ while (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
if (!gst_bin_iterate (GST_BIN (thread))) {
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+ THR_DEBUG_MAIN("removed spinning state due to failed iteration!\n");
}
}
- else {
- GST_DEBUG (0, "thread \"%s\" waiting\n", GST_ELEMENT_NAME (GST_ELEMENT (thread)));
- gst_thread_wait_thread (thread);
+
+ g_mutex_lock (thread->lock);
+
+ if (GST_STATE_PENDING(thread) == GST_STATE_PAUSED) {
+ // we've stopped spinning, because of PLAYING->PAUSED
+ THR_DEBUG_MAIN("SPINNING flag unset, signaling parent process we're stopped\n");
+ // we need to signal back that we've stopped spinning
+ g_cond_signal (thread->cond);
}
+
+// THR_DEBUG_MAIN("signaling that the thread is out of the SPINNING loop\n");
+// g_cond_signal (thread->cond);
+// g_cond_wait (thread->cond, thread->lock);
+// THR_DEBUG_MAIN("parent process has signaled at bottom of while\n");
+// // now change the children's and thread's state
+// gst_thread_update_state (thread);
+// THR_DEBUG_MAIN("done changing state, signaling back to parent process\n");
+// g_cond_signal (thread->cond);
+// // don't release the mutex, we hold that into the top of the loop
+// THR_DEBUG_MAIN("done syncing with parent process at bottom of while\n");
}
+*/
- GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
-// FIXME this should be removed (why's it here???)
-// //pthread_join (thread->thread_id, 0);
+ // since we don't unlock at the end of the while loop, do it here
+ g_mutex_unlock (thread->lock);
GST_INFO (GST_CAT_THREAD, "gstthread: thread \"%s\" is stopped",
GST_ELEMENT_NAME (thread));
return NULL;
}
+// the set flag is to say whether it should set TRUE or FALSE
+//
+// WARNING: this has synchronization built in! if you remove or add any
+// locks, waits, signals, or unlocks you need to be sure they match the
+// code above (in gst_thread_main_loop()). basically, don't change anything.
static void
-gst_thread_signal_thread (GstThread *thread)
+gst_thread_signal_thread (GstThread *thread, gboolean spinning)
{
- GST_DEBUG (0,"signaling thread\n");
- g_mutex_lock (thread->lock);
+ // set the spinning state
+ if (spinning) GST_FLAG_SET(thread,GST_THREAD_STATE_SPINNING);
+ else GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
+
+ THR_DEBUG("thread locked\n");
+// g_mutex_lock(thread->lock);
+
+// if (!spinning) {
+// THR_DEBUG("waiting for spindown\n");
+// g_cond_wait (thread->cond, thread->lock);
+// }
+ THR_DEBUG("signaling\n");
g_cond_signal (thread->cond);
- g_mutex_unlock (thread->lock);
-}
+ THR_DEBUG("waiting for ack\n");
+ g_cond_wait (thread->cond,thread->lock);
+ THR_DEBUG("got ack\n");
-static void
-gst_thread_wait_thread (GstThread *thread)
-{
- GST_DEBUG (0,"waiting for thread\n");
- g_mutex_lock (thread->lock);
- g_cond_wait (thread->cond, thread->lock);
- g_mutex_unlock (thread->lock);
+ THR_DEBUG("unlocking\n");
+ g_mutex_unlock(thread->lock);
+ THR_DEBUG("unlocked\n");
}
@@ -359,7 +669,7 @@ static void
gst_thread_restore_thyself (GstObject *object,
xmlNodePtr self)
{
- GST_DEBUG (0,"gstthread: restore\n");
+ GST_DEBUG (GST_CAT_THREAD,"gstthread: restore\n");
if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
GST_OBJECT_CLASS (parent_class)->restore_thyself (object, self);
diff --git a/gst/gstthread.h b/gst/gstthread.h
index 8c53a118a..be8b49cd8 100644
--- a/gst/gstthread.h
+++ b/gst/gstthread.h
@@ -24,6 +24,7 @@
#ifndef __GST_THREAD_H__
#define __GST_THREAD_H__
+#include <unistd.h>
#include <pthread.h>
#include <gst/gstbin.h>
@@ -38,8 +39,11 @@ extern GstElementDetails gst_thread_details;
typedef enum {
GST_THREAD_CREATE = GST_BIN_FLAG_LAST,
+
+ GST_THREAD_STATE_STARTED,
GST_THREAD_STATE_SPINNING,
GST_THREAD_STATE_REAPING,
+ GST_THREAD_STATE_ELEMENT_CHANGED,
/* padding */
GST_THREAD_FLAG_LAST = GST_BIN_FLAG_LAST + 4,
@@ -64,8 +68,12 @@ struct _GstThread {
GstBin bin;
pthread_t thread_id; /* id of the thread, if any */
+ gint pid; /* the pid of the thread */
+ gint ppid; /* the pid of the thread's parent process */
GMutex *lock; /* thread lock/condititon pair... */
GCond *cond; /* used to control the thread */
+
+ gint transition; /* the current state transition */
};
struct _GstThreadClass {
@@ -74,7 +82,7 @@ struct _GstThreadClass {
GtkType gst_thread_get_type (void);
-GstElement* gst_thread_new (guchar *name);
+GstElement* gst_thread_new (const guchar *name);
#ifdef __cplusplus
}
diff --git a/gst/gsttype.c b/gst/gsttype.c
index 437da194d..744089885 100644
--- a/gst/gsttype.c
+++ b/gst/gsttype.c
@@ -80,7 +80,7 @@ gst_type_register (GstTypeFactory *factory)
_gst_types = g_list_prepend (_gst_types, type);
id = type->id;
- GST_DEBUG (0,"gsttype: new mime type '%s', id %d\n", type->mime, type->id);
+ GST_DEBUG (GST_CAT_TYPES,"gsttype: new mime type '%s', id %d\n", type->mime, type->id);
} else {
type = gst_type_find_by_id (id);
@@ -108,12 +108,12 @@ guint16 gst_type_find_by_mime_func (const gchar *mime)
g_return_val_if_fail (mime != NULL, 0);
walk = _gst_types;
-// GST_DEBUG (0,"searching for '%s'\n",mime);
+// GST_DEBUG (GST_CAT_TYPES,"searching for '%s'\n",mime);
mimelen = strlen (mime);
while (walk) {
type = (GstType *)walk->data;
search = type->mime;
-// GST_DEBUG (0,"checking against '%s'\n",search);
+// GST_DEBUG (GST_CAT_TYPES,"checking against '%s'\n",search);
typelen = strlen (search);
while ((search - type->mime) < typelen) {
found = strstr (search, mime);
@@ -232,7 +232,7 @@ gst_type_typefind_dummy (GstBuffer *buffer, gpointer priv)
guint16 typeid;
GSList *funcs;
- GST_DEBUG (0,"gsttype: need to load typefind function for %s\n", type->mime);
+ GST_DEBUG (GST_CAT_TYPES,"gsttype: need to load typefind function for %s\n", type->mime);
type->typefindfuncs = NULL;
gst_plugin_load_typefactory (type->mime);
diff --git a/gst/gsttypefind.c b/gst/gsttypefind.c
index 78ac04c81..2e045e0b8 100644
--- a/gst/gsttypefind.c
+++ b/gst/gsttypefind.c
@@ -180,11 +180,25 @@ gst_typefind_chain (GstPad *pad, GstBuffer *buf)
GST_DEBUG (0,"try type :%d \"%s\"\n", type->id, type->mime);
if (typefindfunc && (caps = typefindfunc (buf, type))) {
- GST_DEBUG (0,"found type :%d \"%s\"\n", caps->id, type->mime);
+ GST_DEBUG (0,"found type :%d \"%s\" \"%s\"\n", caps->id, type->mime,
+ gst_caps_get_name (caps));
typefind->caps = caps;
+
+ gst_pad_set_caps (pad, caps);
+
+{ /* FIXME: this should all be in an _emit() wrapper eventually */
+ int oldstate = GST_STATE(typefind);
+ gst_object_ref (GST_OBJECT (typefind));
gtk_signal_emit (GTK_OBJECT (typefind), gst_typefind_signals[HAVE_TYPE],
typefind->caps);
- gst_pad_set_caps (pad, caps);
+ if (GST_STATE(typefind) != oldstate) {
+ gst_object_unref (GST_OBJECT (typefind));
+ GST_DEBUG(0, "state changed during signal, aborting\n");
+ cothread_switch(cothread_current_main());
+ }
+ gst_object_unref (GST_OBJECT (typefind));
+}
+
goto end;
}
funcs = g_slist_next (funcs);
diff --git a/gst/gsttypes.h b/gst/gsttypes.h
new file mode 100644
index 000000000..a7c07ed8f
--- /dev/null
+++ b/gst/gsttypes.h
@@ -0,0 +1,17 @@
+#ifndef __GST_TYPES_H__
+#define __GST_TYPES_H__
+
+typedef struct _GstObject GstObject;
+typedef struct _GstObjectClass GstObjectClass;
+typedef struct _GstPad GstPad;
+typedef struct _GstPadClass GstPadClass;
+typedef struct _GstPadTemplate GstPadTemplate;
+typedef struct _GstPadTemplateClass GstPadTemplateClass;
+typedef struct _GstElement GstElement;
+typedef struct _GstElementClass GstElementClass;
+typedef struct _GstBin GstBin;
+typedef struct _GstBinClass GstBinClass;
+typedef struct _GstSchedule GstSchedule;
+typedef struct _GstScheduleClass GstScheduleClass;
+
+#endif
diff --git a/gst/gstxml.c b/gst/gstxml.c
index 146fda0a7..28f67c9f0 100644
--- a/gst/gstxml.c
+++ b/gst/gstxml.c
@@ -167,7 +167,7 @@ gst_xml_parse_doc (GstXML *xml, xmlDocPtr doc, const guchar *root)
if (!strcmp(field->name, "element") && (field->ns == xml->ns)) {
GstElement *element;
- element = gst_element_load_thyself(field, NULL);
+ element = gst_element_restore_thyself(field, NULL);
xml->topelements = g_list_prepend (xml->topelements, element);
}
diff --git a/gstplay/Makefile.am b/gstplay/Makefile.am
index 7b6dc5477..552490962 100644
--- a/gstplay/Makefile.am
+++ b/gstplay/Makefile.am
@@ -37,6 +37,7 @@ noinst_HEADERS = \
gstplayprivate.h \
full-screen.h
+
libgstmediaplay_la_LDFLAGS = -rdynamic
gstmediaplay_CFLAGS = $(LIBGLADE_GNOME_CFLAGS)
diff --git a/gstplay/gstmediaplay.c b/gstplay/gstmediaplay.c
index 84e2c0f89..e42cc3bfc 100644
--- a/gstplay/gstmediaplay.c
+++ b/gstplay/gstmediaplay.c
@@ -39,12 +39,11 @@ target_drag_data_received (GtkWidget *widget,
guint time,
GstMediaPlay *play)
{
- if (strstr (data->data, "file:")) {
- g_print ("Got: %s\n", &data->data[5]);
- gdk_threads_leave ();
- gst_media_play_start_uri (play, g_strchomp (&data->data[5]));
- gdk_threads_enter ();
- }
+ g_print ("Got: %s\n", data->data);
+ gdk_threads_leave ();
+ gst_media_play_start_uri (play, g_strchomp (data->data));
+ gdk_threads_enter ();
+
}
static GtkTargetEntry target_table[] = {
diff --git a/gstplay/gstmediaplay.glade b/gstplay/gstmediaplay.glade
index 78567a3f2..bdf88d442 100644
--- a/gstplay/gstmediaplay.glade
+++ b/gstplay/gstmediaplay.glade
@@ -508,6 +508,7 @@ Arik Devens &lt;arik@gnome.org&gt;
<last_modification_time>Sun, 06 Aug 2000 15:55:52 GMT</last_modification_time>
</signal>
<stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
+ <relief>GTK_RELIEF_NORMAL</relief>
</widget>
<widget>
@@ -523,6 +524,7 @@ Arik Devens &lt;arik@gnome.org&gt;
<last_modification_time>Sun, 06 Aug 2000 15:53:48 GMT</last_modification_time>
</signal>
<stock_button>GNOME_STOCK_BUTTON_CANCEL</stock_button>
+ <relief>GTK_RELIEF_NORMAL</relief>
</widget>
</widget>
diff --git a/gstplay/gstplay.c b/gstplay/gstplay.c
index 1b8569f24..6cb247765 100644
--- a/gstplay/gstplay.c
+++ b/gstplay/gstplay.c
@@ -1,20 +1,22 @@
#include <config.h>
+#include <string.h>
+
#include "gstplay.h"
#include "gstplayprivate.h"
#include "full-screen.h"
-static void gst_play_class_init (GstPlayClass *klass);
-static void gst_play_init (GstPlay *play);
+static void gst_play_class_init (GstPlayClass *klass);
+static void gst_play_init (GstPlay *play);
-static void gst_play_set_arg (GtkObject *object, GtkArg *arg, guint id);
-static void gst_play_get_arg (GtkObject *object, GtkArg *arg, guint id);
+static void gst_play_set_arg (GtkObject *object, GtkArg *arg, guint id);
+static void gst_play_get_arg (GtkObject *object, GtkArg *arg, guint id);
-static void gst_play_realize (GtkWidget *play);
+static void gst_play_realize (GtkWidget *play);
-static void gst_play_frame_displayed (GstElement *element, GstPlay *play);
-static void gst_play_have_size (GstElement *element, guint width, guint height, GstPlay *play);
-static void gst_play_audio_handoff (GstElement *element, GstPlay *play);
+static void gst_play_frame_displayed (GstElement *element, GstPlay *play);
+static void gst_play_have_size (GstElement *element, guint width, guint height, GstPlay *play);
+static void gst_play_audio_handoff (GstElement *element, GstPlay *play);
/* signals and args */
enum {
@@ -118,10 +120,8 @@ gst_play_init (GstPlay *play)
play->priv = priv;
/* create a new bin to hold the elements */
- priv->thread = gst_thread_new ("main_thread");
- g_assert (priv->thread != NULL);
- priv->bin = gst_bin_new ("main_bin");
- g_assert (priv->bin != NULL);
+ priv->pipeline = gst_pipeline_new ("main_pipeline");
+ g_assert (priv->pipeline != NULL);
priv->audio_element = gst_elementfactory_make ("osssink", "play_audio");
g_return_if_fail (priv->audio_element != NULL);
@@ -165,6 +165,12 @@ gst_play_new ()
return GST_PLAY (gtk_type_new (GST_TYPE_PLAY));
}
+static gboolean
+gst_play_idle_func (gpointer data)
+{
+ return gst_bin_iterate (GST_BIN (data));
+}
+
static void
gst_play_eos (GstElement *element,
GstPlay *play)
@@ -273,53 +279,68 @@ gst_play_object_added (GstAutoplug* autoplug, GstObject *object, GstPlay *play)
}
static void
-gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
+gst_play_cache_empty (GstElement *element, GstPlay *play)
{
- GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
+ GstPlayPrivate *priv;
+ GstElement *new_element;
+
+ priv = (GstPlayPrivate *)play->priv;
+
+ gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+
+ new_element = gst_bin_get_by_name (GST_BIN (priv->pipeline), "new_element");
+
+ gst_element_disconnect (priv->src, "src", priv->cache, "sink");
+ gst_element_disconnect (priv->cache, "src", new_element, "sink");
+ gst_bin_remove (GST_BIN (priv->pipeline), priv->cache);
+ gst_element_connect (priv->src, "src", new_element, "sink");
- *(gboolean *)data = TRUE;
+ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
}
-static GstCaps*
-gst_play_typefind (GstBin *bin, GstElement *element)
+static void
+gst_play_have_type (GstElement *sink, GstCaps *caps, GstPlay *play)
{
- gboolean found = FALSE;
- GstElement *typefind;
- GstCaps *caps = NULL;
+ GstPlayPrivate *priv;
+ GstElement *new_element;
+ GstAutoplug *autoplug;
- GST_DEBUG (0, "GstPipeline: typefind for element \"%s\" %p\n",
- GST_ELEMENT_NAME (element), &found);
+ GST_DEBUG (0,"GstPipeline: play have type\n");
- typefind = gst_elementfactory_make ("typefind", "typefind");
- g_return_val_if_fail (typefind != NULL, FALSE);
+ priv = (GstPlayPrivate *)play->priv;
- gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
- GTK_SIGNAL_FUNC (gst_play_have_type), &found);
+ gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
- gst_pad_connect (gst_element_get_pad (element, "src"),
- gst_element_get_pad (typefind, "sink"));
+ gst_element_disconnect (priv->cache, "src", priv->typefind, "sink");
+ gst_bin_remove (GST_BIN (priv->pipeline), priv->typefind);
- gst_bin_add (bin, typefind);
+ autoplug = gst_autoplugfactory_make ("staticrender");
+ g_assert (autoplug != NULL);
+
+ gtk_signal_connect (GTK_OBJECT (autoplug), "new_object", gst_play_object_added, play);
+
+ new_element = gst_autoplug_to_renderers (autoplug,
+ caps,
+ priv->video_element,
+ priv->audio_element,
+ NULL);
- gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
+ if (!new_element) {
+ // FIXME, signal a suitable error
+ return;
+ }
- // push a buffer... the have_type signal handler will set the found flag
- gst_bin_iterate (bin);
+ gst_element_set_name (new_element, "new_element");
- gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
+ gst_bin_add (GST_BIN (priv->pipeline), new_element);
- if (found) {
- caps = gst_util_get_pointer_arg (GTK_OBJECT (typefind), "caps");
+ gtk_object_set (GTK_OBJECT (priv->cache), "reset", TRUE, NULL);
- gst_pad_set_caps (gst_element_get_pad (element, "src"), caps);
- }
+ gst_element_connect (priv->cache, "src", new_element, "sink");
- gst_pad_disconnect (gst_element_get_pad (element, "src"),
- gst_element_get_pad (typefind, "sink"));
- gst_bin_remove (bin, typefind);
- gst_object_unref (GST_OBJECT (typefind));
+ gtk_signal_connect (GTK_OBJECT (priv->pipeline), "eos", GTK_SIGNAL_FUNC (gst_play_eos), play);
- return caps;
+ gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
}
static gboolean
@@ -349,9 +370,7 @@ GstPlayReturn
gst_play_set_uri (GstPlay *play, const guchar *uri)
{
GstPlayPrivate *priv;
- GstCaps *src_caps;
- GstElement *new_element;
- GstAutoplug *autoplug;
+ gchar* uriloc;
g_return_val_if_fail (play != NULL, GST_PLAY_ERROR);
g_return_val_if_fail (GST_IS_PLAY (play), GST_PLAY_ERROR);
@@ -362,47 +381,51 @@ gst_play_set_uri (GstPlay *play, const guchar *uri)
if (priv->uri)
g_free (priv->uri);
- priv->uri = g_strdup (uri);
- priv->src = gst_elementfactory_make ("disksrc", "disk_src");
- //priv->src = gst_elementfactory_make ("dvdsrc", "disk_src");
- priv->offset_element = priv->src;
+ /* see if it looks like a ARI */
+ if ((uriloc = strstr (uri, ":/"))) {
+ priv->src = gst_elementfactory_make ("gnomevfssrc", "srcelement");
- g_return_val_if_fail (priv->src != NULL, -1);
- gtk_object_set (GTK_OBJECT (priv->src), "location", uri, NULL);
+ if (!priv->src) {
+ if (strstr (uri, "file:/")) {
+ uri += strlen ("file:/");
+ }
+ else
+ return GST_PLAY_CANNOT_PLAY;
+ }
+ }
- gst_bin_add (GST_BIN (priv->bin), priv->src);
+ if (priv->src == NULL) {
+ priv->src = gst_elementfactory_make ("disksrc", "srcelement");
+ }
- src_caps = gst_play_typefind (GST_BIN (priv->bin), priv->src);
+ priv->uri = g_strdup (uri);
- if (!src_caps) {
- return GST_PLAY_UNKNOWN_MEDIA;
- }
+ //priv->src = gst_elementfactory_make ("dvdsrc", "disk_src");
+ priv->offset_element = priv->src;
+ g_return_val_if_fail (priv->src != NULL, GST_PLAY_CANNOT_PLAY);
- autoplug = gst_autoplugfactory_make ("staticrender");
- g_assert (autoplug != NULL);
+ gtk_object_set (GTK_OBJECT (priv->src), "location", priv->uri, NULL);
- gtk_signal_connect (GTK_OBJECT (autoplug), "new_object", gst_play_object_added, play);
- new_element = gst_autoplug_to_renderers (autoplug,
- gst_pad_get_caps (gst_element_get_pad (priv->src, "src")),
- priv->video_element,
- priv->audio_element,
- NULL);
+ priv->cache = gst_elementfactory_make ("autoplugcache", "cache");
+ g_return_val_if_fail (priv->cache != NULL, GST_PLAY_CANNOT_PLAY);
- if (!new_element) {
- return GST_PLAY_CANNOT_PLAY;
- }
+ gtk_signal_connect (GTK_OBJECT (priv->cache), "cache_empty",
+ GTK_SIGNAL_FUNC (gst_play_cache_empty), play);
- gst_bin_remove (GST_BIN (priv->bin), priv->src);
- gst_bin_add (GST_BIN (priv->thread), priv->src);
+ priv->typefind = gst_elementfactory_make ("typefind", "typefind");
+ g_return_val_if_fail (priv->typefind != NULL, GST_PLAY_CANNOT_PLAY);
+ gtk_signal_connect (GTK_OBJECT (priv->typefind), "have_type",
+ GTK_SIGNAL_FUNC (gst_play_have_type), play);
- gst_bin_add (GST_BIN (priv->bin), new_element);
- gst_element_connect (priv->src, "src", new_element, "sink");
+ gst_bin_add (GST_BIN (priv->pipeline), priv->src);
+ gst_bin_add (GST_BIN (priv->pipeline), priv->cache);
+ gst_bin_add (GST_BIN (priv->pipeline), priv->typefind);
- gst_bin_add (GST_BIN (priv->thread), priv->bin);
- gtk_signal_connect (GTK_OBJECT (priv->thread), "eos", GTK_SIGNAL_FUNC (gst_play_eos), play);
+ gst_element_connect (priv->src, "src", priv->cache, "sink");
+ gst_element_connect (priv->cache, "src", priv->typefind, "sink");
return GST_PLAY_OK;
}
@@ -449,10 +472,11 @@ gst_play_play (GstPlay *play)
if (play->state == GST_PLAY_PLAYING) return;
if (play->state == GST_PLAY_STOPPED)
- gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_READY);
- gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_PLAYING);
+ gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_READY);
+ gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_PLAYING);
play->state = GST_PLAY_PLAYING;
+ gtk_idle_add (gst_play_idle_func, priv->pipeline);
gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
play->state);
@@ -470,9 +494,10 @@ gst_play_pause (GstPlay *play)
if (play->state != GST_PLAY_PLAYING) return;
- gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_PAUSED);
+ gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_PAUSED);
play->state = GST_PLAY_PAUSED;
+ g_idle_remove_by_data (priv->pipeline);
gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
play->state);
@@ -491,11 +516,12 @@ gst_play_stop (GstPlay *play)
priv = (GstPlayPrivate *)play->priv;
// FIXME until state changes are handled properly
- gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_READY);
+ gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_READY);
gtk_object_set (GTK_OBJECT (priv->src),"offset",0,NULL);
- //gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_NULL);
+ //gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_NULL);
play->state = GST_PLAY_STOPPED;
+ g_idle_remove_by_data (priv->pipeline);
gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
play->state);
@@ -653,7 +679,7 @@ gst_play_get_pipeline (GstPlay *play)
priv = (GstPlayPrivate *)play->priv;
- return GST_ELEMENT (priv->bin);
+ return GST_ELEMENT (priv->pipeline);
}
static void
diff --git a/gstplay/gstplay.h b/gstplay/gstplay.h
index beda5f16d..8356dd1ee 100644
--- a/gstplay/gstplay.h
+++ b/gstplay/gstplay.h
@@ -19,10 +19,10 @@ typedef enum {
} GstPlayState;
typedef enum {
- GST_PLAY_OK,
- GST_PLAY_UNKNOWN_MEDIA,
- GST_PLAY_CANNOT_PLAY,
- GST_PLAY_ERROR,
+ GST_PLAY_OK,
+ GST_PLAY_UNKNOWN_MEDIA,
+ GST_PLAY_CANNOT_PLAY,
+ GST_PLAY_ERROR,
} GstPlayReturn;
typedef enum {
diff --git a/gstplay/gstplayprivate.h b/gstplay/gstplayprivate.h
index 763f80af1..2b80f179a 100644
--- a/gstplay/gstplayprivate.h
+++ b/gstplay/gstplayprivate.h
@@ -6,12 +6,13 @@
typedef struct _GstPlayPrivate GstPlayPrivate;
struct _GstPlayPrivate {
- GstElement *thread;
- GstElement *bin;
+ GstElement *pipeline;
GstElement *video_element, *audio_element;
GstElement *video_show;
GtkWidget *video_widget;
GstElement *src;
+ GstElement *cache;
+ GstElement *typefind;
guchar *uri;
gboolean muted;
diff --git a/gstreamer-uninstalled.pc.in b/gstreamer-uninstalled.pc.in
new file mode 100644
index 000000000..0cc88fd90
--- /dev/null
+++ b/gstreamer-uninstalled.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: GStreamer Uninstalled
+Description: Streaming-media framework, Not Installed
+Version: @VERSION@
+Requires: glib gtk+
+Libs: ${pcbuilddir}/${pcfiledir}/gst/libgst.la
+Cflags: -I${pcbuilddir}/${pcfiledir}
diff --git a/gstreamer.pc.in b/gstreamer.pc.in
new file mode 100644
index 000000000..47ed44b0f
--- /dev/null
+++ b/gstreamer.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: GStreamer
+Description: Streaming-media framework
+Requires:
+Version: @VERSION@
+Libs: -L${libdir} -lgst
+Cflags:
diff --git a/gstreamer.spec.in b/gstreamer.spec.in
index 28456b138..6ccff3ea7 100644
--- a/gstreamer.spec.in
+++ b/gstreamer.spec.in
@@ -84,3 +84,4 @@ make prefix=$RPM_BUILD_ROOT%{prefix} install
%{prefix}/include/*
%{prefix}/lib/lib*.a
%{prefix}/lib/lib*.so
+%{prefix}/lib/pkgconfig/*
diff --git a/libs/idct/gstidct.c b/libs/idct/gstidct.c
index 39b3cfcf9..ae180e363 100644
--- a/libs/idct/gstidct.c
+++ b/libs/idct/gstidct.c
@@ -53,38 +53,38 @@ GstIDCT *gst_idct_new(GstIDCTMethod method)
switch (method) {
case GST_IDCT_FAST_INT:
- GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using fast_int_idct\n");
+ GST_INFO (GST_CAT_PLUGIN_INFO, "using fast_int_idct");
gst_idct_init_fast_int_idct();
new->convert = gst_idct_fast_int_idct;
break;
case GST_IDCT_INT:
- GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using int_idct\n");
+ GST_INFO (GST_CAT_PLUGIN_INFO, "using int_idct");
new->convert = gst_idct_int_idct;
break;
case GST_IDCT_FLOAT:
- GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using float_idct\n");
+ GST_INFO (GST_CAT_PLUGIN_INFO, "using float_idct");
gst_idct_init_float_idct();
new->convert = gst_idct_float_idct;
break;
#ifdef HAVE_LIBMMX
case GST_IDCT_MMX:
- GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using MMX_idct\n");
+ GST_INFO (GST_CAT_PLUGIN_INFO, "using MMX_idct");
new->convert = gst_idct_mmx_idct;
new->need_transpose = TRUE;
break;
case GST_IDCT_MMX32:
- GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using MMX32_idct\n");
+ GST_INFO (GST_CAT_PLUGIN_INFO, "using MMX32_idct");
new->convert = gst_idct_mmx32_idct;
new->need_transpose = TRUE;
break;
case GST_IDCT_SSE:
- GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using SSE_idct\n");
+ GST_INFO (GST_CAT_PLUGIN_INFO, "using SSE_idct");
new->convert = gst_idct_sse_idct;
new->need_transpose = TRUE;
break;
#endif /* HAVE_LIBMMX */
default:
- GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: method not supported\n");
+ GST_INFO (GST_CAT_PLUGIN_INFO, "method not supported");
g_free(new);
return NULL;
}
diff --git a/plugins/elements/gstfakesrc.c b/plugins/elements/gstfakesrc.c
index 5fa6af217..97570bbb8 100644
--- a/plugins/elements/gstfakesrc.c
+++ b/plugins/elements/gstfakesrc.c
@@ -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();
diff --git a/plugins/elements/gstfakesrc.h b/plugins/elements/gstfakesrc.h
index a795c1932..ba92f631b 100644
--- a/plugins/elements/gstfakesrc.h
+++ b/plugins/elements/gstfakesrc.h
@@ -65,6 +65,7 @@ struct _GstFakeSrc {
GstElement element;
gboolean loop_based;
+ gboolean eos;
gint numsrcpads;
GSList *srcpads;
GstFakeSrcOutputType output;
diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c
index 37a4f7f3c..755c8f8c2 100644
--- a/plugins/elements/gstqueue.c
+++ b/plugins/elements/gstqueue.c
@@ -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;
diff --git a/plugins/elements/gstqueue.h b/plugins/elements/gstqueue.h
index 606346735..085d5ac12 100644
--- a/plugins/elements/gstqueue.h
+++ b/plugins/elements/gstqueue.h
@@ -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);
diff --git a/plugins/elements/gstsinesrc.c b/plugins/elements/gstsinesrc.c
index 8cddd5d7b..6a00e1eef 100644
--- a/plugins/elements/gstsinesrc.c
+++ b/plugins/elements/gstsinesrc.c
@@ -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
+}
diff --git a/test/.gitignore b/test/.gitignore
index 81021e48c..89626b4d5 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -29,6 +29,7 @@ mp3parse
mpeg2parse
mpeg2parse2
mpeg2parse3
+mpeg2parse4
mp3play
ac3parse
ac3play
diff --git a/test/Makefile.am b/test/Makefile.am
index ea89a6a5b..50f7a8fb2 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -22,18 +22,6 @@ ac3play_SOURCES = ac3play.c mem.c
noinst_HEADERS = mem.h
-if HAVE_LIBXV
-xvlibs=-lXv
-else
-xvlibs=
-endif
-
-LDADD = ${xvlibs} -lXxf86vm $(GNOME_LIBS) $(GST_LIBS)
-
-#LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la \
-# $(top_builddir)/plugins/videosink/libvideosink.la -L/usr/X11/lib -lXxf86dga
-#LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la
-
LIBS += $(GNOME_LIBS) $(GST_LIBS)
CFLAGS += $(GNOME_CFLAGS) $(GST_CFLAGS)
diff --git a/test/avi2mpg.c b/test/avi2mpg.c
index 866162982..1d64a9ab9 100644
--- a/test/avi2mpg.c
+++ b/test/avi2mpg.c
@@ -141,7 +141,7 @@ int main(int argc,char *argv[]) {
g_return_val_if_fail(src != NULL, -1);
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
g_print("should be using file '%s'\n",argv[1]);
- parse = gst_elementfactory_make("parseavi","parse");
+ parse = gst_elementfactory_make("avidecoder","parse");
g_return_val_if_fail(parse != NULL, -1);
mux = gst_elementfactory_make("system_encode","mux");
diff --git a/test/cobin.c b/test/cobin.c
index 7f9630959..3f45ca45c 100644
--- a/test/cobin.c
+++ b/test/cobin.c
@@ -32,8 +32,6 @@ int main(int argc,char *argv[]) {
gst_pad_connect(gst_element_get_pad(identity,"src"),
gst_element_get_pad(sink,"sink"));
- g_print("--- creating a plan\n");
- gst_bin_create_plan(GST_BIN(bin));
g_print("--- starting up\n");
gst_bin_iterate(GST_BIN(bin));
diff --git a/test/dvshow.c b/test/dvshow.c
index 45fc498fc..b6b462aec 100644
--- a/test/dvshow.c
+++ b/test/dvshow.c
@@ -29,7 +29,7 @@ main (int argc,char *argv[])
gnome_init("Videotest","0.0.1",argc,argv);
- bin = gst_bin_new("bin");
+ bin = gst_pipeline_new("pipeline");
if (argc == 1) {
src = gst_elementfactory_make ("dv1394src", "src");
diff --git a/test/fake.c b/test/fake.c
index d24efa9de..2910d94b3 100644
--- a/test/fake.c
+++ b/test/fake.c
@@ -10,7 +10,7 @@ int main(int argc,char *argv[]) {
// _gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
- bin = gst_bin_new("bin");
+ bin = gst_pipeline_new("pipeline");
g_return_if_fail(bin != NULL);
g_print("--- creating src and sink elements\n");
@@ -35,8 +35,6 @@ int main(int argc,char *argv[]) {
g_print("--- setting up\n");
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_READY);
- g_print("--- creating plan\n");
- gst_bin_create_plan(bin);
g_print("--- iterating\n");
gst_bin_iterate(bin);
}
diff --git a/test/mpeg2parse2.c b/test/mpeg2parse2.c
index 176eed35d..75a04c42f 100644
--- a/test/mpeg2parse2.c
+++ b/test/mpeg2parse2.c
@@ -86,6 +86,7 @@ int main(int argc,char *argv[]) {
gtk_socket = gtk_socket_new ();
gtk_widget_show (gtk_socket);
+ gtk_widget_set_usize(gtk_socket,320,240);
gnome_app_set_contents(GNOME_APP(appwindow),
GTK_WIDGET(gtk_socket));
diff --git a/test/mpeg2parse3.c b/test/mpeg2parse3.c
index ee2e3d8b4..c74aacfe5 100644
--- a/test/mpeg2parse3.c
+++ b/test/mpeg2parse3.c
@@ -1,8 +1,10 @@
#include <gnome.h>
#include <gst/gst.h>
-GstElement *parse2, *v_queue, *a_queue;
+GstPipeline *pipeline;
+GstElement *v_queue, *a_queue, *v_thread, *a_thread;
GtkWidget *appwindow;
+GtkWidget *gtk_socket;
void eof(GstElement *src) {
g_print("have eos, quitting\n");
@@ -17,38 +19,37 @@ gboolean idle_func(gpointer data) {
void mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) {
g_print("***** a new pad %s was created\n", gst_pad_get_name(pad));
- gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PAUSED);
if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) {
gst_pad_connect(pad, gst_element_get_pad(v_queue,"sink"));
+ gst_bin_add(GST_BIN(pipeline),v_thread);
+ gst_element_set_state(v_thread,GST_STATE_PLAYING);
} else if (strcmp(gst_pad_get_name(pad), "private_stream_1.0") == 0) {
gst_pad_connect(pad, gst_element_get_pad(a_queue,"sink"));
+ gst_bin_add(GST_BIN(pipeline),a_thread);
+ gst_element_set_state(a_thread,GST_STATE_PLAYING);
}
- gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
+}
+
+void mpeg2parse_have_size(GstElement *videosink,gint width,gint height) {
+ gtk_widget_set_usize(gtk_socket,width,height);
+ gtk_widget_show_all(appwindow);
}
int main(int argc,char *argv[]) {
- GstPipeline *pipeline;
GstElement *src, *parse;
- GstElement *v_thread, *v_decode, *show, *color;
- GstElement *a_thread, *a_decode, *osssink;
- GtkWidget *gtk_socket;
+ GstElement *v_decode, *show, *color;
+ GstElement *a_decode, *osssink;
g_print("have %d args\n",argc);
gst_init(&argc,&argv);
gnome_init("MPEG2 Video player","0.0.1",argc,argv);
- //gst_plugin_load("mpeg1parse");
+ // ***** construct the main pipeline *****
pipeline = GST_PIPELINE(gst_pipeline_new("pipeline"));
g_return_val_if_fail(pipeline != NULL, -1);
- v_thread = GST_ELEMENT(gst_thread_new("v_thread"));
- g_return_val_if_fail(v_thread != NULL, -1);
-
- a_thread = GST_ELEMENT(gst_thread_new("a_thread"));
- g_return_val_if_fail(a_thread != NULL, -1);
-
if (strstr(argv[1],"video_ts")) {
src = gst_elementfactory_make("dvdsrc","src");
g_print("using DVD source\n");
@@ -68,20 +69,19 @@ int main(int argc,char *argv[]) {
//parse = gst_elementfactory_make("mpeg1parse","parse");
g_return_val_if_fail(parse != NULL, -1);
+ gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
+ gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
+
+ gst_element_connect(src,"src",parse,"sink");
+
+
+ // ***** pre-construct the video thread *****
+ v_thread = GST_ELEMENT(gst_thread_new("v_thread"));
+ g_return_val_if_fail(v_thread != NULL, -1);
+
v_queue = gst_elementfactory_make("queue","v_queue");
g_return_val_if_fail(v_queue != NULL, -1);
-
- a_queue = gst_elementfactory_make("queue","a_queue");
- g_return_val_if_fail(a_queue != NULL, -1);
-
- /****
- * you can substitute mpeg2play with you own player here
- * optionally you can remove the parse2 element. make
- * sure to remove the pad connections too and don't add the
- * mp2videoparse element to the bin.
- **/
- //parse2 = gst_elementfactory_make("mp2videoparse","parse");
- //g_return_val_if_fail(parse2 != NULL, -1);
+
v_decode = gst_elementfactory_make("mpeg2dec","decode_video");
g_return_val_if_fail(v_decode != NULL, -1);
@@ -89,16 +89,40 @@ int main(int argc,char *argv[]) {
g_return_val_if_fail(color != NULL, -1);
show = gst_elementfactory_make("xvideosink","show");
- //show = gst_elementfactory_make("aasink","show");
- //gtk_object_set(GTK_OBJECT(show),"xv_enabled",FALSE,NULL);
g_return_val_if_fail(show != NULL, -1);
+ gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_queue));
+ gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_decode));
+ gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(color));
+ gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(show));
+
+ gst_element_connect(v_queue,"src",v_decode,"sink");
+ gst_element_connect(v_decode,"src",color,"sink");
+ gst_element_connect(color,"src",show,"sink");
+
+
+ // ***** pre-construct the audio thread *****
+ a_thread = GST_ELEMENT(gst_thread_new("a_thread"));
+ g_return_val_if_fail(a_thread != NULL, -1);
+
+ a_queue = gst_elementfactory_make("queue","a_queue");
+ g_return_val_if_fail(a_queue != NULL, -1);
+
a_decode = gst_elementfactory_make("ac3dec","decode_audio");
g_return_val_if_fail(a_decode != NULL, -1);
osssink = gst_elementfactory_make("osssink","osssink");
g_return_val_if_fail(osssink != NULL, -1);
+ gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_queue));
+ gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_decode));
+ gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(osssink));
+
+ gst_element_connect(a_queue,"src",a_decode,"sink");
+ gst_element_connect(a_decode,"src",osssink,"sink");
+
+
+ // ***** construct the GUI *****
appwindow = gnome_app_new("MPEG player","MPEG player");
gtk_socket = gtk_socket_new ();
@@ -111,45 +135,9 @@ int main(int argc,char *argv[]) {
gtk_socket_steal (GTK_SOCKET (gtk_socket),
gst_util_get_int_arg (GTK_OBJECT(show), "xid"));
- gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
- gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
- gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(v_queue));
-
- //gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(parse2));
- gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_decode));
- gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(color));
- gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(show));
-
- gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_decode));
- gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(osssink));
-
- gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(v_thread));
- gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(a_thread));
-
gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad, pipeline);
-
gtk_signal_connect(GTK_OBJECT(src),"eos",GTK_SIGNAL_FUNC(eof),NULL);
-
- gst_pad_connect(gst_element_get_pad(src,"src"),
- gst_element_get_pad(parse,"sink"));
-
- // video
- gst_pad_connect(gst_element_get_pad(v_queue,"src"),
- // gst_element_get_pad(parse2,"sink"));
- //gst_pad_connect(gst_element_get_pad(parse2,"src"),
- gst_element_get_pad(v_decode,"sink"));
- gst_pad_connect(gst_element_get_pad(v_decode,"src"),
- gst_element_get_pad(color,"sink"));
- gst_pad_connect(gst_element_get_pad(color,"src"),
- gst_element_get_pad(show,"sink"));
-
- // audio
- gst_pad_connect(gst_element_get_pad(a_queue,"src"),
- gst_element_get_pad(a_decode,"sink"));
- gst_pad_connect(gst_element_get_pad(a_decode,"src"),
- gst_element_get_pad(osssink,"sink"));
-
- gtk_widget_show_all(appwindow);
+ gtk_signal_connect(GTK_OBJECT(show),"have_size",mpeg2parse_have_size, pipeline);
g_print("setting to PLAYING state\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
diff --git a/test/mpeg2parse4.c b/test/mpeg2parse4.c
new file mode 100644
index 000000000..f918a11ac
--- /dev/null
+++ b/test/mpeg2parse4.c
@@ -0,0 +1,224 @@
+#include <gnome.h>
+#include <gst/gst.h>
+
+GstElement *pipeline, *src, *parse;
+GstElement *v_decode_thread, *v_decode_queue, *v_decode, *v_color;
+GstElement *v_show_thread, *v_show_queue, *v_show;
+GstElement *a_decode_thread, *a_decode_queue, *a_decode;
+GstElement *a_sink_thread, *a_sink_queue, *a_sink;
+GtkWidget *appwindow;
+GtkWidget *gtk_socket;
+
+void eof(GstElement *src) {
+ fprintf(stderr,"have eos, quitting\n");
+ exit(0);
+}
+
+gboolean idle_func(gpointer data) {
+ gst_bin_iterate(GST_BIN(data));
+ return TRUE;
+}
+
+int mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) {
+
+ fprintf(stderr,"***** a new pad %s was created\n", gst_pad_get_name(pad));
+
+ if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) {
+
+ // build the decoder thread
+ v_decode_thread = GST_ELEMENT(gst_thread_new("v_decode_thread"));
+ g_return_val_if_fail(v_decode_thread != NULL, -1);
+
+ v_decode_queue = gst_elementfactory_make("queue","v_decode_queue");
+ g_return_val_if_fail(v_decode_queue != NULL, -1);
+
+ v_decode = gst_elementfactory_make("mpeg2dec","v_decode");
+ g_return_val_if_fail(v_decode != NULL, -1);
+
+ v_color = gst_elementfactory_make("colorspace","v_color");
+ g_return_val_if_fail(v_color != NULL, -1);
+
+ gst_bin_add(GST_BIN(v_decode_thread),GST_ELEMENT(v_decode_queue));
+ gst_bin_add(GST_BIN(v_decode_thread),GST_ELEMENT(v_decode));
+ gst_bin_add(GST_BIN(v_decode_thread),GST_ELEMENT(v_color));
+
+ gst_element_connect(v_decode_queue,"src",v_decode,"sink");
+ gst_element_connect(v_decode,"src",v_color,"sink");
+
+ gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
+
+
+ // build the show thread
+ v_show_thread = GST_ELEMENT(gst_thread_new("v_show_thread"));
+ g_return_val_if_fail(v_show_thread != NULL, -1);
+
+ v_show_queue = gst_elementfactory_make("queue","v_show_queue");
+ g_return_val_if_fail(v_show_queue != NULL, -1);
+
+ // v_show has ben created earlier
+
+ gst_bin_add(GST_BIN(v_show_thread),GST_ELEMENT(v_show_queue));
+ gst_bin_add(GST_BIN(v_show_thread),GST_ELEMENT(v_show));
+
+ gst_element_connect(v_show_queue,"src",v_show,"sink");
+
+
+ // now assemble the decoder threads
+ gst_bin_add(GST_BIN(v_decode_thread),v_show_thread);
+ gst_element_connect(v_color,"src",v_show_queue,"sink");
+
+ gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
+ gst_schedule_show(GST_ELEMENT_SCHED(v_show_thread));
+
+ // connect the whole thing to the main pipeline
+ gst_pad_connect(pad, gst_element_get_pad(v_decode_queue,"sink"));
+ gst_bin_add(GST_BIN(pipeline),v_decode_thread);
+
+ gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
+ gst_schedule_show(GST_ELEMENT_SCHED(v_show_thread));
+
+ // start it playing
+ gst_element_set_state(v_decode_thread,GST_STATE_PLAYING);
+
+ } else if (strcmp(gst_pad_get_name(pad), "private_stream_1.0") == 0) {
+ // build the decoder thread
+ a_decode_thread = GST_ELEMENT(gst_thread_new("a_decode_thread"));
+ g_return_val_if_fail(a_decode_thread != NULL, -1);
+
+ a_decode_queue = gst_elementfactory_make("queue","a_decode_queue");
+ g_return_val_if_fail(a_decode_queue != NULL, -1);
+
+ a_decode = gst_elementfactory_make("ac3dec","a_decode");
+ g_return_val_if_fail(a_decode != NULL, -1);
+
+ gst_bin_add(GST_BIN(a_decode_thread),GST_ELEMENT(a_decode_queue));
+ gst_bin_add(GST_BIN(a_decode_thread),GST_ELEMENT(a_decode));
+
+ gst_element_connect(a_decode_queue,"src",a_decode,"sink");
+
+ gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
+
+
+ // build the sink thread
+ a_sink_thread = GST_ELEMENT(gst_thread_new("a_sink_thread"));
+ g_return_val_if_fail(a_sink_thread != NULL, -1);
+
+ a_sink_queue = gst_elementfactory_make("queue","a_sink_queue");
+ g_return_val_if_fail(a_sink_queue != NULL, -1);
+
+ a_sink = gst_elementfactory_make("esdsink","a_sink");
+ g_return_val_if_fail(a_sink != NULL, -1);
+
+ gst_bin_add(GST_BIN(a_sink_thread),GST_ELEMENT(a_sink_queue));
+ gst_bin_add(GST_BIN(a_sink_thread),GST_ELEMENT(a_sink));
+
+ gst_element_connect(a_sink_queue,"src",a_sink,"sink");
+
+
+ // now assemble the decoder threads
+ gst_bin_add(GST_BIN(a_decode_thread),a_sink_thread);
+ gst_element_connect(a_decode,"src",a_sink_queue,"sink");
+
+ gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
+ gst_schedule_show(GST_ELEMENT_SCHED(a_sink_thread));
+
+ // connect the whole thing to the main pipeline
+ gst_pad_connect(pad, gst_element_get_pad(a_decode_queue,"sink"));
+ gst_bin_add(GST_BIN(pipeline),a_decode_thread);
+
+ gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
+ gst_schedule_show(GST_ELEMENT_SCHED(a_sink_thread));
+
+ // start it playing
+ gst_element_set_state(a_decode_thread,GST_STATE_PLAYING);
+
+ }
+
+ if (v_decode_thread && a_decode_thread) {
+ xmlSaveFile("mpeg2parse4.gst", gst_xml_write(GST_ELEMENT(pipeline)));
+fprintf(stderr,"DUMP OF ALL SCHEDULES!!!:\n");
+ gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
+ gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
+ gst_schedule_show(GST_ELEMENT_SCHED(v_show_thread));
+ gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
+ gst_schedule_show(GST_ELEMENT_SCHED(a_sink_thread));
+ }
+
+ return 0;
+}
+
+void mpeg2parse_have_size(GstElement *videosink,gint width,gint height) {
+ gtk_widget_set_usize(gtk_socket,width,height);
+ gtk_widget_show_all(appwindow);
+}
+
+int main(int argc,char *argv[]) {
+
+ g_print("have %d args\n",argc);
+
+ gst_init(&argc,&argv);
+ gnome_init("MPEG2 Video player","0.0.1",argc,argv);
+
+ // ***** construct the main pipeline *****
+ pipeline = gst_pipeline_new("pipeline");
+ g_return_val_if_fail(pipeline != NULL, -1);
+
+ if (strstr(argv[1],"video_ts")) {
+ src = gst_elementfactory_make("dvdsrc","src");
+ g_print("using DVD source\n");
+ } else {
+ src = gst_elementfactory_make("disksrc","src");
+ }
+
+ g_return_val_if_fail(src != NULL, -1);
+ gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
+ if (argc >= 3) {
+ gtk_object_set(GTK_OBJECT(src),"bytesperread",atoi(argv[2]),NULL);
+ g_print("block size is %d\n",atoi(argv[2]));
+ }
+ g_print("should be using file '%s'\n",argv[1]);
+
+ parse = gst_elementfactory_make("mpeg2parse","parse");
+ //parse = gst_elementfactory_make("mpeg1parse","parse");
+ g_return_val_if_fail(parse != NULL, -1);
+
+ gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
+ gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
+
+ gst_element_connect(src,"src",parse,"sink");
+
+
+ // create v_show early so we can get and connect stuff
+ v_show = gst_elementfactory_make("xvideosink","v_show");
+ g_return_val_if_fail(v_show != NULL, -1);
+
+
+
+ // ***** construct the GUI *****
+ appwindow = gnome_app_new("MPEG player","MPEG player");
+
+ gtk_socket = gtk_socket_new ();
+ gtk_widget_show (gtk_socket);
+
+ gnome_app_set_contents(GNOME_APP(appwindow),
+ GTK_WIDGET(gtk_socket));
+
+ gtk_widget_realize (gtk_socket);
+ gtk_socket_steal (GTK_SOCKET (gtk_socket),
+ gst_util_get_int_arg (GTK_OBJECT(v_show), "xid"));
+
+ gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad, pipeline);
+ gtk_signal_connect(GTK_OBJECT(src),"eos",GTK_SIGNAL_FUNC(eof),NULL);
+ gtk_signal_connect(GTK_OBJECT(v_show),"have_size",mpeg2parse_have_size, pipeline);
+
+ fprintf(stderr,"setting to PLAYING state\n");
+ gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
+
+ gtk_idle_add(idle_func,pipeline);
+
+ gdk_threads_enter();
+ gtk_main();
+ gdk_threads_leave();
+
+ return 0;
+}
diff --git a/test/video2mp1.c b/test/video2mp1.c
index 79b3a50c9..786f76535 100644
--- a/test/video2mp1.c
+++ b/test/video2mp1.c
@@ -54,7 +54,6 @@ gst_play_typefind (GstBin *bin, GstElement *element)
gst_pad_disconnect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_remove (bin, typefind);
- gst_object_unref (GST_OBJECT (typefind));
return caps;
}
@@ -174,6 +173,7 @@ int main(int argc,char *argv[])
exit (-1);
}
+ gst_object_ref (GST_OBJECT (disksrc));
gst_bin_remove (GST_BIN (bin), disksrc);
gst_object_destroy (GST_OBJECT (bin));
diff --git a/test/videotest2.c b/test/videotest2.c
index c830cc8ff..0f69f44d1 100644
--- a/test/videotest2.c
+++ b/test/videotest2.c
@@ -27,7 +27,7 @@ main (int argc,char *argv[])
gnome_init("Videotest","0.0.1",argc,argv);
- bin = gst_bin_new("bin");
+ bin = gst_pipeline_new("pipeline");
src = gst_elementfactory_make ("v4lsrc", "src");
gtk_object_set(GTK_OBJECT(src),"format",9,NULL);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c30852d59..11ce4da68 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,8 +1,8 @@
-SUBDIRS = sched eos
+SUBDIRS = sched eos
noinst_PROGRAMS = init loadall simplefake states caps queue registry \
paranoia rip mp3encode autoplug props case4 markup load tee autoplug2 autoplug3 \
-capsconnect padfactory autoplug4
+capsconnect padfactory autoplug4 incsched reaping threadlock mp1vid
# we have nothing but apps here, we can do this safely
LIBS += $(GST_LIBS)
diff --git a/tests/incsched.c b/tests/incsched.c
new file mode 100644
index 000000000..f73b6171d
--- /dev/null
+++ b/tests/incsched.c
@@ -0,0 +1,135 @@
+#include <stdlib.h>
+#include <gst/gst.h>
+
+int main(int argc,char *argv[]) {
+ GstBin *thread, *bin;
+ GstElement *src, *identity, *sink, *identity2;
+
+ gst_init(&argc,&argv);
+ gst_info_set_categories(-1);
+ gst_debug_set_categories(-1);
+
+ g_print("\n\nConstructing stuff:\n");
+ thread = gst_pipeline_new("thread");
+ bin = gst_bin_new("bin");
+ src = gst_elementfactory_make("fakesrc","src");
+ identity = gst_elementfactory_make("identity","identity");
+ sink = gst_elementfactory_make("fakesink","sink");
+ identity2 = gst_elementfactory_make("identity","identity2");
+
+ g_print("\nAdding src to thread:\n");
+ gst_bin_add(thread,src);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nAdding identity to thread:\n");
+ gst_bin_add(thread,identity);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nRemoving identity from thread:\n");
+ gst_bin_remove(thread, identity);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nAdding identity to thread:\n");
+ gst_bin_add(thread,identity);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nConnecting src to identity:\n");
+ gst_element_connect(src,"src",identity,"sink");
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nDisconnecting src from identity:\n");
+ gst_element_disconnect(src,"src",identity,"sink");
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nConnecting src to identity:\n");
+ gst_element_connect(src,"src",identity,"sink");
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nAdding sink to bin:\n");
+ gst_bin_add(bin,sink);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nAdding bin to thread:\n");
+ gst_bin_add(thread, GST_ELEMENT(bin));
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nConnecting identity to sink:\n");
+ gst_element_connect(identity,"src",sink,"sink");
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nDisconnecting sink:\n");
+ gst_element_disconnect(identity,"src",sink,"sink");
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nAdding identity2 to bin:\n");
+ gst_bin_add(bin, identity2);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nConnecting identity2 to sink\n");
+ gst_element_connect(identity2,"src",sink,"sink");
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nConnecting identity to identity2\n");
+ gst_element_connect(identity,"src",identity2,"sink");
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\n\nNow setting state from NULL to READY:\n");
+ gst_element_set_state(GST_ELEMENT(thread),GST_STATE_READY);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\n\nNow setting state from READY to PLAYING:\n");
+ gst_element_set_state(GST_ELEMENT(thread),GST_STATE_PLAYING);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\n\nIterating:\n");
+ gst_bin_iterate(thread);
+
+ g_print("\n\nNow setting state from PLAYING to READY:\n");
+ gst_element_set_state(GST_ELEMENT(thread),GST_STATE_READY);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\n\nNow setting state from READY to PLAYING:\n");
+ gst_element_set_state(GST_ELEMENT(thread),GST_STATE_PLAYING);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\n\nIterating:\n");
+ gst_bin_iterate(thread);
+
+ g_print("\n\nNow setting state from PLAYING to READY:\n");
+ gst_element_set_state(GST_ELEMENT(thread),GST_STATE_READY);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nDisconnecting identity from identity2:\n");
+ gst_element_disconnect(identity,"src",identity2,"sink");
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nDisconnecting identity2 from sink:\n");
+ gst_element_disconnect(identity2,"src",sink,"sink");
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\nConnecting identity to sink:\n");
+ gst_element_connect(identity,"src",sink,"sink");
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\n\nNow setting identity2 to NULL:\n");
+ gst_element_set_state(identity2,GST_STATE_NULL);
+
+ g_print("\nRemoving identity2 from bin:\n");
+ gst_bin_remove(bin, identity2);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\n\nNow setting state from READY to PLAYING:\n");
+ gst_element_set_state(GST_ELEMENT(thread),GST_STATE_PLAYING);
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ g_print("\n\nIterating:\n");
+ gst_bin_iterate(thread);
+
+//return;
+ g_print("\n\nSetting EOS on fakesrc and iterating again:\n");
+ gtk_object_set(GTK_OBJECT(src),"eos",TRUE,NULL);
+ gst_bin_iterate(thread);
+
+ g_print("\n\nIterating:\n");
+ gst_bin_iterate(thread);
+}
diff --git a/tests/mp1vid.c b/tests/mp1vid.c
new file mode 100644
index 000000000..2ad61b420
--- /dev/null
+++ b/tests/mp1vid.c
@@ -0,0 +1,78 @@
+#include <gst/gst.h>
+
+GstElement *audiothread;
+GstElement *audioqueue;
+GstElement *audiodecode;
+GstElement *audiosink;
+
+void new_pad(GstElement *parse,GstPad *pad,GstElement *pipeline) {
+
+ if (!strncmp(gst_pad_get_name(pad), "audio_", 6)) {
+ fprintf(stderr,"have audio pad\n");
+
+ fprintf(stderr,"creating thread\n");
+ audiothread = gst_elementfactory_make("thread","audiothread");
+ gst_bin_add(GST_BIN(pipeline),audiothread);
+
+ fprintf(stderr,"creating queue\n");
+ audioqueue = gst_elementfactory_make("queue","audioqueue");
+ gst_bin_add(GST_BIN(audiothread),audioqueue);
+ gst_pad_connect(pad,gst_element_get_pad(audioqueue,"sink"));
+
+ fprintf(stderr,"creating decoder\n");
+ audiodecode = gst_elementfactory_make("mad","audiodecode");
+ gst_bin_add(GST_BIN(audiothread),audiodecode);
+ gst_element_connect(audioqueue,"src",audiodecode,"sink");
+
+ fprintf(stderr,"creating esdsink\n");
+ audiosink = gst_elementfactory_make("osssink","audiosink");
+ gst_bin_add(GST_BIN(audiothread),audiosink);
+ gst_element_connect(audiodecode,"src",audiosink,"sink");
+
+ fprintf(stderr,"setting state to PLAYING\n");
+ gst_element_set_state(audiothread,GST_STATE_PLAYING);
+
+ fprintf(stderr,"done dealing with new audio pad\n");
+ }
+}
+
+int main(int argc,char *argv[]) {
+ GstElement *pipeline, *sourcethread, *src, *parse;
+ int i;
+
+ gst_init(&argc,&argv);
+
+ pipeline = gst_pipeline_new("pipeline");
+ sourcethread = gst_elementfactory_make("thread","sourcethread");
+ src = gst_elementfactory_make("disksrc","src");
+ gtk_object_set(GTK_OBJECT(src),"location","/home/omega/media/AlienSong.mpg",NULL);
+ parse = gst_elementfactory_make("mpeg1parse","parse");
+
+ gtk_signal_connect(GTK_OBJECT(parse),"new_pad",
+ GTK_SIGNAL_FUNC(new_pad),pipeline);
+
+ gst_bin_add(GST_BIN(sourcethread),src);
+ gst_bin_add(GST_BIN(sourcethread),parse);
+
+ gst_element_connect(src,"src",parse,"sink");
+
+ gst_bin_add(GST_BIN(pipeline),sourcethread);
+
+ gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
+
+ gst_element_set_state(pipeline,GST_STATE_PLAYING);
+ sleep(1);
+
+ while (1) {
+// sleep(1);
+fprintf(stderr,"setting to PAUSED\n");
+ gst_element_set_state(pipeline,GST_STATE_PAUSED);fprintf(stderr,"paused... ");
+// sleep(1);
+fprintf(stderr,"setting to PLAYING\n");
+ gst_element_set_state(pipeline,GST_STATE_PLAYING);fprintf(stderr,"playing.\n");
+ }
+
+// for (i=0;i<10;i++)
+// while (1)
+// gst_bin_iterate(GST_BIN(pipeline));
+}
diff --git a/tests/old/examples/Makefile.am b/tests/old/examples/Makefile.am
index c251eabb6..a97088356 100644
--- a/tests/old/examples/Makefile.am
+++ b/tests/old/examples/Makefile.am
@@ -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
diff --git a/tests/old/examples/autoplug/autoplug.c b/tests/old/examples/autoplug/autoplug.c
index e9135fb8d..70ac4b7a2 100644
--- a/tests/old/examples/autoplug/autoplug.c
+++ b/tests/old/examples/autoplug/autoplug.c
@@ -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);
}
diff --git a/tests/old/examples/mixer/mixer.c b/tests/old/examples/mixer/mixer.c
index 205d0738a..4461d4796 100644
--- a/tests/old/examples/mixer/mixer.c
+++ b/tests/old/examples/mixer/mixer.c
@@ -4,10 +4,13 @@
* demonstrates the adder plugin and the volume envelope plugin
* work in progress but do try it out
*
- * Latest change : 16/04/2001
- * multiple input channels allowed
- * volume envelope adapted
- * Version : 0.3
+ * Latest change : 28/04/2001
+ * trying to adapt to incsched
+ * delayed start for channels > 1
+ * now works by quickhacking the
+ * adder plugin to set
+ * GST_ELEMENT_COTHREAD_STOPPING
+ * Version : 0.5
*/
#include <stdlib.h>
@@ -15,8 +18,10 @@
#include "mixer.h"
#include <unistd.h>
+//#define WITH_BUG
+//#define WITH_BUG2
//#define DEBUG
-
+//#define AUTOPLUG /* define if you want autoplugging of input channels */
/* function prototypes */
input_channel_t* create_input_channel (int id, char* location);
@@ -35,55 +40,50 @@ void eos(GstElement *element)
// playing = FALSE;
}
-static void
-gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
-{
- GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
-
- *(gboolean *)data = TRUE;
-}
-
static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element)
{
- gboolean found = FALSE;
GstElement *typefind;
+ GstElement *pipeline;
GstCaps *caps = NULL;
- GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
- GST_ELEMENT_NAME(element), &found);
+ GST_DEBUG (0,"GstPipeline: typefind for element \"%s\"\n",
+ GST_ELEMENT_NAME(element));
+
+ pipeline = gst_pipeline_new ("autoplug_pipeline");
typefind = gst_elementfactory_make ("typefind", "typefind");
g_return_val_if_fail (typefind != NULL, FALSE);
- gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
- GTK_SIGNAL_FUNC (gst_play_have_type), &found);
-
gst_pad_connect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_add (bin, typefind);
+ gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (bin));
- gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
// push a buffer... the have_type signal handler will set the found flag
- gst_bin_iterate (bin);
+ gst_bin_iterate (GST_BIN (pipeline));
- gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
+ gst_element_set_state (pipeline, GST_STATE_NULL);
caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
gst_pad_disconnect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_remove (bin, typefind);
+ gst_bin_remove (GST_BIN (pipeline), GST_ELEMENT (bin));
gst_object_unref (GST_OBJECT (typefind));
+ gst_object_unref (GST_OBJECT (pipeline));
return caps;
}
int main(int argc,char *argv[])
{
- int i;
+ int i, j;
int num_channels;
+ gboolean done;
char buffer[20];
@@ -108,38 +108,41 @@ int main(int argc,char *argv[])
/* set up output channel and main bin */
/* create adder */
- adder = gst_elementfactory_make("adder", "adderel");
+ adder = gst_elementfactory_make ("adder", "adderel");
/* create an audio sink */
- audiosink = gst_elementfactory_make("esdsink", "play_audio");
+ audiosink = gst_elementfactory_make ("esdsink", "play_audio");
/* create main bin */
- main_bin = gst_bin_new("bin");
+ main_bin = gst_pipeline_new("bin");
/* connect adder and output to bin */
-
- gst_bin_add(GST_BIN(main_bin), adder);
- gst_bin_add(GST_BIN(main_bin), audiosink);
+ GST_INFO (0, "main: adding adder to bin");
+ gst_bin_add (GST_BIN(main_bin), adder);
+ GST_INFO (0, "main: adding audiosink to bin");
+ gst_bin_add (GST_BIN(main_bin), audiosink);
/* connect adder and audiosink */
gst_pad_connect(gst_element_get_pad(adder,"src"),
gst_element_get_pad(audiosink,"sink"));
- /* create input channels, add to bin and connect */
-
+ /* start looping */
input_channels = NULL;
for (i = 1; i < argc; ++i)
{
printf ("Opening channel %d from file %s...\n", i, argv[i]);
channel_in = create_input_channel (i, argv[i]);
- input_channels = g_list_append (input_channels, channel_in);
- gst_bin_add(GST_BIN(main_bin), channel_in->pipe);
+ input_channels = g_list_append (input_channels, channel_in);
+
+ if (i > 1) gst_element_set_state (main_bin, GST_STATE_PAUSED);
+ gst_bin_add (GST_BIN(main_bin), channel_in->pipe);
/* request pads and connect to adder */
+ GST_INFO (0, "requesting pad\n");
pad = gst_element_request_pad_by_name (adder, "sink%d");
- g_print ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
+ printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
sprintf (buffer, "channel%d", i);
gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad);
@@ -178,24 +181,32 @@ int main(int argc,char *argv[])
env_register_cp (channel_in->volenv, num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */
}
env_register_cp (channel_in->volenv, num_channels * 10.0 , 1.0 / num_channels); /* to end level */
- }
-
- /* sleep a few seconds doesn't seem to help anyway */
- printf ("Sleeping a few seconds ...\n");
- sleep (2);
- printf ("Waking up ...\n");
+ xmlSaveFile("mixer.xml", gst_xml_write(GST_ELEMENT(main_bin)));
-
- /* start playing */
- gst_element_set_state(main_bin, GST_STATE_PLAYING);
+ /* start playing */
+ gst_element_set_state(main_bin, GST_STATE_PLAYING);
- playing = TRUE;
+ // write out the schedule
+ gst_schedule_show(GST_ELEMENT_SCHED(main_bin));
+ playing = TRUE;
- while (playing) {
+ j = 0;
+ //printf ("main: start iterating from 0");
+ while (playing && j < 100)
+ {
+// printf ("main: iterating %d\n", j);
+ gst_bin_iterate(GST_BIN(main_bin));
+ //fprintf(stderr,"after iterate()\n");
+ ++j;
+ }
+ }
+ printf ("main: all the channels are open\n");
+ while (playing)
+ {
gst_bin_iterate(GST_BIN(main_bin));
+ //fprintf(stderr,"after iterate()\n");
}
-
/* stop the bin */
gst_element_set_state(main_bin, GST_STATE_NULL);
@@ -228,11 +239,10 @@ create_input_channel (int id, char* location)
GstAutoplug *autoplug;
GstCaps *srccaps;
GstElement *new_element;
+ GstElement *decoder;
-#ifdef DEBUG
- printf ("DEBUG : c_i_p : creating channel with id %d for file %s\n",
+ GST_DEBUG (0, "c_i_p : creating channel with id %d for file %s\n",
id, location);
-#endif
/* allocate channel */
@@ -245,23 +255,21 @@ create_input_channel (int id, char* location)
/* create channel */
-#ifdef DEBUG
- printf ("DEBUG : c_i_p : creating pipeline\n");
-#endif
+ GST_DEBUG (0, "c_i_p : creating pipeline\n");
- channel->pipe = gst_bin_new ("pipeline");
+ sprintf (buffer, "pipeline%d", id);
+ channel->pipe = gst_bin_new (buffer);
g_assert(channel->pipe != NULL);
/* create elements */
-#ifdef DEBUG
- printf ("DEBUG : c_i_p : creating disksrc\n");
-#endif
+ GST_DEBUG(0, "c_i_p : creating disksrc\n");
sprintf (buffer, "disksrc%d", id);
channel->disksrc = gst_elementfactory_make ("disksrc", buffer);
g_assert(channel->disksrc != NULL);
-
+
+ GST_DEBUG(0, "c_i_p : setting location\n");
gtk_object_set(GTK_OBJECT(channel->disksrc),"location", location, NULL);
/* add disksrc to the bin before autoplug */
@@ -286,8 +294,24 @@ create_input_channel (int id, char* location)
printf ("DEBUG : c_i_p : getting srccaps\n");
#endif
+#ifdef WITH_BUG
srccaps = gst_play_typefind (GST_BIN (channel->pipe), channel->disksrc);
+#endif
+#ifdef WITH_BUG2
+ {
+ GstElement *pipeline;
+ pipeline = gst_pipeline_new ("autoplug_pipeline");
+
+ gst_bin_add (GST_BIN (pipeline), channel->pipe);
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN (pipeline), channel->pipe);
+
+ }
+#endif
+
+#ifdef AUTOPLUG
if (!srccaps) {
g_print ("could not autoplug, unknown media type...\n");
exit (-1);
@@ -311,7 +335,24 @@ create_input_channel (int id, char* location)
g_print ("could not autoplug, no suitable codecs found...\n");
exit (-1);
}
+
+#else
+
+ new_element = gst_bin_new ("autoplug_bin");
+
+ /* static plug, use mad plugin and assume mp3 input */
+ decoder = gst_elementfactory_make ("mad", "mpg123");
+
+ gst_bin_add (GST_BIN (new_element), decoder);
+
+ gst_element_add_ghost_pad (new_element,
+ gst_element_get_pad (decoder, "sink"), "sink");
+ gst_element_add_ghost_pad (new_element,
+ gst_element_get_pad (decoder, "src"), "src_00");
+#endif
+ xmlSaveFile ("mixer.gst", gst_xml_write (new_element));
+
gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
gst_bin_add (GST_BIN (channel->pipe), new_element);
diff --git a/tests/old/testsuite/refcounting/Makefile.am b/tests/old/testsuite/refcounting/Makefile.am
new file mode 100644
index 000000000..51df4da64
--- /dev/null
+++ b/tests/old/testsuite/refcounting/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS =
+
+testprogs = object element pad element_pad bin thread
+
+object_SOURCES = object.c mem.c
+element_SOURCES = element.c mem.c
+pad_SOURCES = pad.c mem.c
+element_pad_SOURCES = element_pad.c mem.c
+bin_SOURCES = bin.c mem.c
+thread_SOURCES = thread.c mem.c
+
+TESTS = $(testprogs)
+
+check_PROGRAMS = $(testprogs)
+
+# we have nothing but apps here, we can do this safely
+LIBS += $(GST_LIBS)
+CFLAGS += $(GST_CFLAGS)
diff --git a/tests/old/testsuite/refcounting/bin.c b/tests/old/testsuite/refcounting/bin.c
new file mode 100644
index 000000000..16c7eb15d
--- /dev/null
+++ b/tests/old/testsuite/refcounting/bin.c
@@ -0,0 +1,272 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_bin (void)
+{
+ GstElement *bin;
+ GstElement *element;
+
+ bin = gst_bin_new ("testbin");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ gst_bin_add (GST_BIN (bin), element);
+ element = gst_element_new ();
+ gst_element_set_name (element, "test2");
+ gst_bin_add (GST_BIN (bin), element);
+
+ return bin;
+}
+
+static GstElement*
+create_bin_ghostpads (void)
+{
+ GstElement *bin;
+ GstElement *element1, *element2;
+
+ bin = gst_bin_new ("testbin");
+ element1 = gst_element_new ();
+ gst_element_set_name (element1, "test1");
+ gst_element_add_pad (element1, gst_pad_new ("src1", GST_PAD_SRC));
+ gst_bin_add (GST_BIN (bin), element1);
+ element2 = gst_element_new ();
+ gst_element_set_name (element2, "test2");
+ gst_element_add_pad (element2, gst_pad_new ("sink1", GST_PAD_SINK));
+ gst_bin_add (GST_BIN (bin), element2);
+ gst_element_connect (element1, "src1", element2, "sink1");
+ gst_element_add_ghost_pad (bin, gst_element_get_pad (element2, "sink1"), "ghost_sink");
+
+ return bin;
+}
+
+static void
+add_remove_test1 (void)
+{
+ GstElement *bin;
+ GstElement *element;
+
+ bin = gst_bin_new ("testbin");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (bin), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ gst_bin_remove (GST_BIN (bin), element);
+
+ gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test2 (void)
+{
+ GstElement *bin;
+ GstElement *element;
+
+ bin = gst_bin_new ("testbin");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ gst_object_ref (GST_OBJECT (element));
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (bin), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ gst_bin_remove (GST_BIN (bin), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ g_assert (!GST_OBJECT_DESTROYED (element));
+
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (GST_OBJECT_DESTROYED (element));
+ gst_object_unref (GST_OBJECT (element));
+
+ gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test3 (void)
+{
+ GstElement *bin;
+ GstElement *element;
+
+ bin = gst_bin_new ("testbin");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (bin), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
+
+ gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test4 (void)
+{
+ GstElement *bin, *bin2;
+ GstElement *element;
+
+ bin = gst_bin_new ("testbin");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (bin), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+
+ bin2 = create_bin ();
+ g_assert (GST_OBJECT_FLOATING (bin2));
+ gst_bin_add (GST_BIN (bin), bin2);
+ g_assert (!GST_OBJECT_FLOATING (bin2));
+
+ gst_object_destroy (GST_OBJECT (bin2));
+ g_assert (gst_bin_get_by_name (GST_BIN (bin), "testbin") == NULL);
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
+
+ gst_object_unref (GST_OBJECT (bin));
+}
+
+int
+main (int argc, gchar *argv[])
+{
+ GstElement *bin;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+ g_print ("starting test\n");
+ usage1 = vmsize();
+
+ bin = gst_bin_new ("somebin");
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("create/unref new bin %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+ bin = gst_bin_new ("somebin");
+ g_assert (GST_OBJECT_FLOATING (bin));
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_sink (GST_OBJECT (bin));
+ g_assert (!GST_OBJECT_FLOATING (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("create/ref/sink/unref new bin %ld\n", vmsize()-usage1);
+
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_sink (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/ref/sink/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+ bin = gst_bin_new ("somebin");
+ g_assert (!GST_OBJECT_DESTROYED (bin));
+ gst_object_destroy (GST_OBJECT (bin));
+ g_assert (GST_OBJECT_DESTROYED (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("create/destroy/unref new bin %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_destroy (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/destroy/unref %d bin %ld\n", iters, vmsize()-usage1);
+
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("create/ref/unref/unref new bin %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/ref/unref/unref %d bin %ld\n", iters, vmsize()-usage1);
+
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_destroy (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("craete/ref/destroy/unref/unref new bin %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_destroy (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_element_set_name (bin, "testing123");
+ gst_object_destroy (GST_OBJECT (bin));
+ gst_element_set_name (bin, "testing123");
+ gst_object_unref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d bins with name %ld\n", iters, vmsize()-usage1);
+
+ bin = gst_bin_new ("somebin");
+ for (i=0; i<iters;i++) {
+ gst_element_set_name (bin, "testing");
+ }
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = create_bin();
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/unref %d bin with children %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters/2;i++) {
+ bin = create_bin_ghostpads();
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/unref %d bin with children and ghostpads %ld\n", iters/2, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test1();
+ }
+ g_print ("add/remove test1 %d in bin %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test2();
+ }
+ g_print ("add/remove test2 %d in bin %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test3();
+ }
+ g_print ("add/destroy/remove test3 %d in bin %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test4();
+ }
+ g_print ("add/destroy/remove test4 %d in bin %ld\n", iters, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/tests/old/testsuite/refcounting/element.c b/tests/old/testsuite/refcounting/element.c
new file mode 100644
index 000000000..f61ffbcd4
--- /dev/null
+++ b/tests/old/testsuite/refcounting/element.c
@@ -0,0 +1,116 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+ GstElement *element;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+ g_print ("starting test\n");
+ usage1 = vmsize();
+
+ element = gst_element_new ();
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("create/unref new element %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+ element = gst_element_new ();
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_sink (GST_OBJECT (element));
+ g_assert (!GST_OBJECT_FLOATING (element));
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("create/ref/sink/unref new element %ld\n", vmsize()-usage1);
+
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_sink (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/ref/sink/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+ element = gst_element_new ();
+ g_assert (!GST_OBJECT_DESTROYED (element));
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (GST_OBJECT_DESTROYED (element));
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("create/destroy/unref new element %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_destroy (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/destroy/unref %d element %ld\n", iters, vmsize()-usage1);
+
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("create/ref/unref/unref new element %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/ref/unref/unref %d element %ld\n", iters, vmsize()-usage1);
+
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_destroy (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("craete/ref/destroy/unref/unref new element %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_destroy (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_element_set_name (element, "testing123");
+ gst_object_destroy (GST_OBJECT (element));
+ gst_element_set_name (element, "testing123");
+ gst_object_unref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d elements with name %ld\n", iters, vmsize()-usage1);
+
+ element = gst_element_new ();
+ for (i=0; i<iters;i++) {
+ gst_element_set_name (element, "testing");
+ }
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/tests/old/testsuite/refcounting/element_pad.c b/tests/old/testsuite/refcounting/element_pad.c
new file mode 100644
index 000000000..0f80291d6
--- /dev/null
+++ b/tests/old/testsuite/refcounting/element_pad.c
@@ -0,0 +1,134 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_element (gchar *padname, GstPadDirection dir)
+{
+ GstElement *element;
+ GstPad *pad;
+
+ element = gst_element_new ();
+ pad = gst_pad_new (padname, dir);
+ gst_element_add_pad (element, pad);
+
+ return element;
+}
+
+int
+main (int argc, gchar *argv[])
+{
+ GstElement *element;
+ GstElement *element2;
+ GstPad *pad;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+
+ g_print ("starting element with pad test with %d iterations\n", iters);
+ usage1 = vmsize();
+
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ g_assert (GST_OBJECT_FLOATING (element));
+ g_assert (!GST_OBJECT_FLOATING (pad));
+ g_assert (gst_pad_get_parent (pad) == element);
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("create/addpad/unref new element %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/addpad/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ element2 = create_element ("src", GST_PAD_SRC);
+ gst_element_connect (element, "sink", element2, "src");
+ g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+ g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element, "sink")));
+ gst_object_unref (GST_OBJECT (element));
+ g_assert (!GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+ gst_object_unref (GST_OBJECT (element2));
+ }
+ g_print ("create/connect/unref %d elements %ld\n", iters/2, vmsize()-usage1);
+
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ element2 = create_element ("src", GST_PAD_SRC);
+ gst_element_connect (element, "sink", element2, "src");
+ g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+ g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element, "sink")));
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (GST_OBJECT_DESTROYED (element));
+ g_assert (!GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+ gst_object_unref (GST_OBJECT (element2));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/connect/destroy %d elements %ld\n", iters/2, vmsize()-usage1);
+
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_element_remove_pad (element, pad);
+ g_assert (gst_element_get_pad (element, "sink") == NULL);
+
+ g_print ("pad removal ok %ld\n", vmsize()-usage1);
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_element_remove_pad (element, pad);
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("pad removal loop %d %ld\n", iters/2, vmsize()-usage1);
+
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_object_ref (GST_OBJECT (pad));
+ gst_element_remove_pad (element, pad);
+ g_assert (gst_pad_get_parent (pad) == NULL);
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("pad removal and test loop %d %ld\n", iters/2, vmsize()-usage1);
+
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (GST_OBJECT_DESTROYED (element));
+ g_assert (gst_element_get_pad (element, "sink") == NULL);
+ gst_object_unref (GST_OBJECT (element));
+
+ g_print ("pad destroy/removal ok %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_object_destroy (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("pad destroy/removal loop %d %ld\n", iters/2, vmsize()-usage1);
+
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_object_destroy (GST_OBJECT (pad));
+ g_assert (gst_element_get_pad (element, "sink") == NULL);
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("pad destroy loop %d %ld\n", iters/2, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/tests/old/testsuite/refcounting/mem.c b/tests/old/testsuite/refcounting/mem.c
new file mode 100644
index 000000000..8e1c573bd
--- /dev/null
+++ b/tests/old/testsuite/refcounting/mem.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int vmsize() {
+ int pid,fd,size,i,mem;
+ char filename[17], buf[256], *ptr, *end;
+
+ pid = getpid();
+ snprintf(filename,17,"/proc/%d/stat",pid);
+ fd = open(filename,O_RDONLY);
+ size = read(fd,buf,240);
+ ptr = buf;
+ for (i=0;i<22;i++)
+ ptr = (char *)strchr(ptr,' ') + 1;
+ end = (char *)strchr(ptr,' ');
+ *end = 0;
+ sscanf(ptr,"%d",&mem);
+ close(fd);
+ return mem;
+}
diff --git a/tests/old/testsuite/refcounting/mem.h b/tests/old/testsuite/refcounting/mem.h
new file mode 100644
index 000000000..28999db2c
--- /dev/null
+++ b/tests/old/testsuite/refcounting/mem.h
@@ -0,0 +1 @@
+int vmsize();
diff --git a/tests/old/testsuite/refcounting/object.c b/tests/old/testsuite/refcounting/object.c
new file mode 100644
index 000000000..477ec9b5d
--- /dev/null
+++ b/tests/old/testsuite/refcounting/object.c
@@ -0,0 +1,156 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+ GstObject *object, *object2;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+ g_print ("starting test with %d iterations\n", iters);
+ usage1 = vmsize();
+ object = gst_object_new ();
+ gst_object_unref (object);
+ g_print ("create/unref new object %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_unref (object);
+
+ }
+ g_print ("create/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ g_assert (GST_OBJECT_FLOATING (object));
+ gst_object_ref (object);
+ gst_object_sink (object);
+ g_assert (!GST_OBJECT_FLOATING (object));
+ gst_object_unref (object);
+ g_print ("create/ref/sink/unref new object %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_sink (object);
+ gst_object_unref (object);
+ }
+ g_print ("create/ref/sink/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ g_assert (!GST_OBJECT_DESTROYED (object));
+ gst_object_destroy (object);
+ g_assert (GST_OBJECT_DESTROYED (object));
+ gst_object_unref (object);
+ g_print ("create/destroy/unref new object %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_destroy (object);
+ gst_object_unref (object);
+ }
+ g_print ("destroy/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_unref (object);
+ gst_object_unref (object);
+ g_print ("create/ref/unref/unref new object %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_unref (object);
+ gst_object_unref (object);
+ }
+ g_print ("create/ref/unref/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_destroy (object);
+ gst_object_unref (object);
+ gst_object_unref (object);
+ g_print ("create/ref/destroy/unref/unref new object %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_destroy (object);
+ gst_object_unref (object);
+ gst_object_unref (object);
+ }
+ g_print ("create/ref/destroy/unref/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_set_name (object, "testing123");
+ gst_object_destroy (object);
+ gst_object_set_name (object, "testing123");
+ gst_object_unref (object);
+ gst_object_unref (object);
+ }
+ g_print ("create/ref/destroy/unref/unref %d object with name %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ for (i=0; i<iters;i++) {
+ gst_object_set_name (object, "testing");
+ }
+ gst_object_unref (object);
+ g_print ("create/set name/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ object2 = gst_object_new ();
+ g_assert (GST_OBJECT_FLOATING (object));
+ g_assert (GST_OBJECT_FLOATING (object2));
+
+ gst_object_set_parent (object, object2);
+ g_assert (GST_OBJECT_FLOATING (object2));
+ g_assert (!GST_OBJECT_FLOATING (object));
+
+ g_print ("parentage flags set_parent ok %ld\n", vmsize()-usage1);
+
+ gst_object_ref (object);
+ gst_object_unparent (object);
+ g_assert (GST_OBJECT_FLOATING (object2));
+ g_assert (!GST_OBJECT_FLOATING (object));
+ g_assert (gst_object_get_parent (object) == NULL);
+
+ g_print ("parentage flags unparent ok %ld\n", vmsize()-usage1);
+
+ gst_object_set_parent (object, object2);
+ g_assert (GST_OBJECT_FLOATING (object2));
+ g_assert (!GST_OBJECT_FLOATING (object));
+ g_assert (gst_object_get_parent (object) == object2);
+
+ gst_object_destroy (object);
+ g_assert (GST_OBJECT_DESTROYED (object));
+ g_assert (!GST_OBJECT_FLOATING (object));
+ g_assert (gst_object_get_parent (object) == NULL);
+ gst_object_unref (object);
+
+ g_print ("parentage flags destroy ok %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ object2 = gst_object_new ();
+ gst_object_set_parent (object2, object);
+ gst_object_unref (object);
+ gst_object_unref (object2);
+ }
+ g_print ("create/unref %d 2 parented objects %ld\n", iters, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/tests/old/testsuite/refcounting/pad.c b/tests/old/testsuite/refcounting/pad.c
new file mode 100644
index 000000000..fed2554cb
--- /dev/null
+++ b/tests/old/testsuite/refcounting/pad.c
@@ -0,0 +1,223 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+ GstPad *pad;
+ GstPad *pad2;
+ GstPadTemplate *padtempl;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+ g_print ("starting pad test\n");
+ usage1 = vmsize();
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("create/unref new pad %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ g_assert (GST_OBJECT_FLOATING (pad));
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_sink (GST_OBJECT (pad));
+ g_assert (!GST_OBJECT_FLOATING (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("create/ref/sink/unref new pad %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_sink (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/ref/sink/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ g_assert (!GST_OBJECT_DESTROYED (pad));
+ gst_object_destroy (GST_OBJECT (pad));
+ g_assert (GST_OBJECT_DESTROYED (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("create/destroy/unref pad %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_destroy (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/destroy/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("create/ref/unref/unref pad %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/ref/unref/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_destroy (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("create/ref/destroy/unref/unref pad %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_destroy (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/ref/destroy/unref/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_pad_set_name (pad, "testing123");
+ gst_object_destroy (GST_OBJECT (pad));
+ gst_pad_set_name (pad, "testing123");
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/ref/destroy/unref/unref %d pads %ld with name\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ for (i=0; i<iters;i++) {
+ gst_pad_set_name (pad, "testing");
+ }
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+ gst_pad_connect (pad2, pad);
+ g_assert (GST_PAD_CONNECTED (pad));
+ g_assert (GST_PAD_CONNECTED (pad2));
+ gst_pad_disconnect (pad2, pad);
+ g_assert (!GST_PAD_CONNECTED (pad));
+ g_assert (!GST_PAD_CONNECTED (pad2));
+ g_print ("connect/disconnect pad %ld\n", vmsize()-usage1);
+ gst_pad_connect (pad, pad2);
+ g_assert (GST_PAD_CONNECTED (pad));
+ g_assert (GST_PAD_CONNECTED (pad2));
+ gst_pad_disconnect (pad, pad2);
+ g_assert (!GST_PAD_CONNECTED (pad));
+ g_assert (!GST_PAD_CONNECTED (pad2));
+ g_print ("connect/disconnect pad wrong direction %ld\n", vmsize()-usage1);
+
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad2));
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+ gst_pad_connect (pad2, pad);
+ gst_pad_disconnect (pad2, pad);
+ gst_pad_connect (pad, pad2);
+ gst_pad_disconnect (pad, pad2);
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad2));
+ }
+ g_print ("connect/disconnect %d pads %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+ gst_pad_connect (pad2, pad);
+ g_assert (GST_PAD_CONNECTED (pad2));
+ g_assert (GST_PAD_CONNECTED (pad));
+
+ gst_object_unref (GST_OBJECT (pad2));
+ g_assert (!GST_PAD_CONNECTED (pad));
+ g_assert (!GST_OBJECT_DESTROYED (pad));
+ gst_object_unref (GST_OBJECT (pad));
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+ gst_pad_connect (pad2, pad);
+ g_assert (GST_PAD_CONNECTED (pad2));
+ g_assert (GST_PAD_CONNECTED (pad));
+
+ gst_object_unref (GST_OBJECT (pad));
+ g_assert (!GST_PAD_CONNECTED (pad2));
+ g_assert (!GST_OBJECT_DESTROYED (pad2));
+ gst_object_unref (GST_OBJECT (pad2));
+
+ g_print ("pad unref effects on connect pad ok %ld\n", vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+ gst_pad_connect (pad2, pad);
+ g_assert (GST_PAD_CONNECTED (pad2));
+ g_assert (GST_PAD_CONNECTED (pad));
+
+ gst_object_destroy (GST_OBJECT (pad2));
+ g_assert (GST_OBJECT_DESTROYED (pad2));
+ g_assert (!GST_OBJECT_DESTROYED (pad));
+ g_assert (!GST_PAD_CONNECTED (pad));
+ gst_object_unref (GST_OBJECT (pad2));
+ g_assert (!GST_OBJECT_DESTROYED (pad));
+ g_assert (!GST_PAD_CONNECTED (pad));
+ gst_object_unref (GST_OBJECT (pad));
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+ gst_pad_connect (pad2, pad);
+ g_assert (GST_PAD_CONNECTED (pad2));
+ g_assert (GST_PAD_CONNECTED (pad));
+
+ gst_object_destroy (GST_OBJECT (pad));
+ g_assert (GST_OBJECT_DESTROYED (pad));
+ g_assert (!GST_OBJECT_DESTROYED (pad2));
+ g_assert (!GST_PAD_CONNECTED (pad2));
+ gst_object_unref (GST_OBJECT (pad));
+ g_assert (!GST_OBJECT_DESTROYED (pad2));
+ g_assert (!GST_PAD_CONNECTED (pad2));
+ gst_object_unref (GST_OBJECT (pad2));
+
+ g_print ("pad destroy effects on connect pad ok %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ padtempl = gst_padtemplate_new ("sink%d", GST_PAD_SINK, GST_PAD_SOMETIMES, NULL);
+ gst_object_unref (GST_OBJECT (padtempl));
+ }
+ g_print ("%d padtemplates create/unref %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ padtempl = gst_padtemplate_new ("sink%d", GST_PAD_SINK, GST_PAD_SOMETIMES, NULL);
+ pad = gst_pad_new_from_template (padtempl, "sink1");
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("%d pads create/unref from padtemplate %ld\n", iters, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return vmsize()-usage1;
+}
diff --git a/tests/old/testsuite/refcounting/thread.c b/tests/old/testsuite/refcounting/thread.c
new file mode 100644
index 000000000..f229a54c6
--- /dev/null
+++ b/tests/old/testsuite/refcounting/thread.c
@@ -0,0 +1,281 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_thread (void)
+{
+ GstElement *thread;
+ GstElement *element;
+
+ thread = gst_thread_new ("testthread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ gst_bin_add (GST_BIN (thread), element);
+ element = gst_element_new ();
+ gst_element_set_name (element, "test2");
+ gst_bin_add (GST_BIN (thread), element);
+
+ return thread;
+}
+
+static GstElement*
+create_thread_ghostpads (void)
+{
+ GstElement *thread;
+ GstElement *element1, *element2;
+
+ thread = gst_thread_new ("testthread");
+ element1 = gst_element_new ();
+ gst_element_set_name (element1, "test1");
+ gst_element_add_pad (element1, gst_pad_new ("src1", GST_PAD_SRC));
+ gst_bin_add (GST_BIN (thread), element1);
+ element2 = gst_element_new ();
+ gst_element_set_name (element2, "test2");
+ gst_element_add_pad (element2, gst_pad_new ("sink1", GST_PAD_SINK));
+ gst_bin_add (GST_BIN (thread), element2);
+ gst_element_connect (element1, "src1", element2, "sink1");
+ gst_element_add_ghost_pad (thread, gst_element_get_pad (element2, "sink1"), "sink1");
+
+ return thread;
+}
+
+static void
+add_remove_test1 (void)
+{
+ GstElement *thread;
+ GstElement *element;
+
+ thread = gst_thread_new ("testthread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (thread), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ gst_bin_remove (GST_BIN (thread), element);
+
+ gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test2 (void)
+{
+ GstElement *thread;
+ GstElement *element;
+
+ thread = gst_thread_new ("testthread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ gst_object_ref (GST_OBJECT (element));
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (thread), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ gst_bin_remove (GST_BIN (thread), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ g_assert (!GST_OBJECT_DESTROYED (element));
+
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (GST_OBJECT_DESTROYED (element));
+ gst_object_unref (GST_OBJECT (element));
+
+ gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test3 (void)
+{
+ GstElement *thread;
+ GstElement *element;
+
+ thread = gst_thread_new ("testthread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (thread), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (gst_bin_get_by_name (GST_BIN (thread), "test1") == NULL);
+
+ gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test4 (void)
+{
+ GstElement *thread, *thread2;
+ GstElement *element;
+
+ thread = gst_thread_new ("testthread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (thread), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+
+ thread2 = create_thread ();
+ g_assert (GST_OBJECT_FLOATING (thread2));
+ gst_bin_add (GST_BIN (thread), thread2);
+ g_assert (!GST_OBJECT_FLOATING (thread2));
+
+ gst_object_destroy (GST_OBJECT (thread2));
+ g_assert (gst_bin_get_by_name (GST_BIN (thread), "testthread") == NULL);
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (gst_bin_get_by_name (GST_BIN (thread), "test1") == NULL);
+
+ gst_object_unref (GST_OBJECT (thread));
+}
+
+int
+main (int argc, gchar *argv[])
+{
+ GstElement *thread, *element;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+ g_print ("starting test\n");
+ usage1 = vmsize();
+
+ thread = gst_thread_new ("somethread");
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("create/unref new thread %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+ thread = gst_thread_new ("somethread");
+ g_assert (GST_OBJECT_FLOATING (thread));
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_sink (GST_OBJECT (thread));
+ g_assert (!GST_OBJECT_FLOATING (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("create/ref/sink/unref new thread %ld\n", vmsize()-usage1);
+
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_sink (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/ref/sink/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+ thread = gst_thread_new ("somethread");
+ g_assert (!GST_OBJECT_DESTROYED (thread));
+ gst_object_destroy (GST_OBJECT (thread));
+ g_assert (GST_OBJECT_DESTROYED (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("create/destroy/unref new thread %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_destroy (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/destroy/unref %d thread %ld\n", iters, vmsize()-usage1);
+
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("create/ref/unref/unref new thread %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/ref/unref/unref %d thread %ld\n", iters, vmsize()-usage1);
+
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_destroy (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("craete/ref/destroy/unref/unref new thread %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_destroy (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_element_set_name (thread, "testing123");
+ gst_object_destroy (GST_OBJECT (thread));
+ gst_element_set_name (thread, "testing123");
+ gst_object_unref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d threads with name %ld\n", iters, vmsize()-usage1);
+
+ thread = gst_thread_new ("somethread");
+ for (i=0; i<iters;i++) {
+ gst_element_set_name (thread, "testing");
+ }
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ gst_bin_add (GST_BIN (thread), element);
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/unref %d thread with one element %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = create_thread();
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/unref %d thread with children %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters/2;i++) {
+ thread = create_thread_ghostpads();
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/unref %d thread with children and ghostpads %ld\n", iters/2, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test1();
+ }
+ g_print ("add/remove test1 %d in thread %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test2();
+ }
+ g_print ("add/remove test2 %d in thread %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test3();
+ }
+ g_print ("add/destroy/remove test3 %d in thread %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test4();
+ }
+ g_print ("add/destroy/remove test4 %d in thread %ld\n", iters, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/tests/reaping.c b/tests/reaping.c
new file mode 100644
index 000000000..3714e54dc
--- /dev/null
+++ b/tests/reaping.c
@@ -0,0 +1,35 @@
+#include <stdio.h>
+#include <gst/gst.h>
+
+int main(int argc,char *argv[]) {
+ GstBin *pipeline, *thread;
+ GstElement *src, *queue1, *sink;
+
+ gst_init(&argc,&argv);
+ gst_info_set_categories(-1);
+ gst_debug_set_categories(-1);
+
+ pipeline = gst_pipeline_new("pipeline");
+ thread = gst_thread_new("thread");
+ src = gst_elementfactory_make("fakesrc","src");
+ queue1 = gst_elementfactory_make("queue","queue");
+ sink = gst_elementfactory_make("fakesink","sink");
+
+ gst_bin_add(pipeline,src);
+ gst_bin_add(pipeline,queue1);
+ gst_bin_add(pipeline,GST_ELEMENT(thread));
+ gst_bin_add(thread,sink);
+
+ gst_element_add_ghost_pad(GST_ELEMENT(thread),gst_element_get_pad(sink,"sink"),"sink");
+
+ gst_element_connect (src,"src",queue1,"sink");
+ gst_element_connect (queue1, "src", thread, "sink");
+
+
+ fprintf(stderr,"\n\n\n");
+ gst_element_set_state (pipeline, GST_STATE_READY);
+
+
+ fprintf(stderr,"\n\n\n");
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+}
diff --git a/tests/states.c b/tests/states.c
index 3d5b6accf..26dbc7491 100644
--- a/tests/states.c
+++ b/tests/states.c
@@ -2,7 +2,7 @@
gboolean state_change(GstElement *element,GstElementState state) {
g_print(">STATES: element '%s' state set to %d(%s)\n",
- gst_element_get_name(element),state,_gst_print_statename(state));
+ gst_element_get_name(element),state,gst_element_statename(state));
g_print(">STATES: element state is actually %d\n",GST_STATE(element));
return TRUE;
@@ -37,15 +37,15 @@ int main(int argc,char *argv[]) {
GTK_SIGNAL_FUNC(state_change),NULL);
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(src),
- GST_STATE(src),_gst_print_statename(GST_STATE(src)));
+ GST_STATE(src),gst_element_statename(GST_STATE(src)));
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(subbin),
- GST_STATE(subbin),_gst_print_statename(GST_STATE(subbin)));
+ GST_STATE(subbin),gst_element_statename(GST_STATE(subbin)));
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(filter),
- GST_STATE(filter),_gst_print_statename(GST_STATE(filter)));
+ GST_STATE(filter),gst_element_statename(GST_STATE(filter)));
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(sink),
- GST_STATE(sink),_gst_print_statename(GST_STATE(sink)));
+ GST_STATE(sink),gst_element_statename(GST_STATE(sink)));
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(bin),
- GST_STATE(bin),_gst_print_statename(GST_STATE(bin)));
+ GST_STATE(bin),gst_element_statename(GST_STATE(bin)));
gst_bin_add(GST_BIN(subbin),filter);
gst_element_add_ghost_pad(GST_ELEMENT(bin),gst_element_get_pad(filter,"sink"),"sink");
diff --git a/tests/threadlock.c b/tests/threadlock.c
new file mode 100644
index 000000000..83b62aa6b
--- /dev/null
+++ b/tests/threadlock.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <gst/gst.h>
+
+int main(int argc,char *argv[]) {
+ GstBin *pipeline, *thread;
+ GstElement *src, *queue1, *sink;
+
+ gst_init(&argc,&argv);
+ gst_info_set_categories(-1);
+ gst_debug_set_categories(-1);
+
+ pipeline = gst_pipeline_new("pipeline");
+ thread = gst_thread_new("thread");
+ src = gst_elementfactory_make("fakesrc","src");
+ sink = gst_elementfactory_make("fakesink","sink");
+
+ fprintf(stderr,"ADDING src\n");
+ gst_bin_add(thread,src);
+ fprintf(stderr,"ADDING sink\n");
+ gst_bin_add(thread,sink);
+ fprintf(stderr,"ADDING thread\n");
+ gst_bin_add(pipeline,GST_ELEMENT(thread));
+
+// gst_element_add_ghost_pad(GST_ELEMENT(thread),gst_element_get_pad(sink,"sink"),"sink");
+
+ fprintf(stderr,"CONNECTING src to sink\n");
+ gst_element_connect (src, "src", sink, "sink");
+
+ fprintf(stderr,"\nSWITCHING to READY:\n");
+ gst_element_set_state (thread, GST_STATE_READY);
+ fprintf(stderr,"\nPIPELINE sched:\n");
+ gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
+ fprintf(stderr,"\nTHREAD sched:\n");
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+ fprintf(stderr,"\nSWITCHING to PLAYING:\n");
+ gst_element_set_state (thread, GST_STATE_PLAYING);
+ gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+fprintf(stderr,"sleeping...\n");
+sleep(1);
+fprintf(stderr,"done sleeping...\n");
+
+ fprintf(stderr,"\nSWITCHING to READY:\n");
+ gst_element_set_state (thread, GST_STATE_READY);
+ gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
+ gst_schedule_show(GST_ELEMENT_SCHED(thread));
+
+sleep(1);
+}
diff --git a/testsuite/refcounting/Makefile.am b/testsuite/refcounting/Makefile.am
new file mode 100644
index 000000000..51df4da64
--- /dev/null
+++ b/testsuite/refcounting/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS =
+
+testprogs = object element pad element_pad bin thread
+
+object_SOURCES = object.c mem.c
+element_SOURCES = element.c mem.c
+pad_SOURCES = pad.c mem.c
+element_pad_SOURCES = element_pad.c mem.c
+bin_SOURCES = bin.c mem.c
+thread_SOURCES = thread.c mem.c
+
+TESTS = $(testprogs)
+
+check_PROGRAMS = $(testprogs)
+
+# we have nothing but apps here, we can do this safely
+LIBS += $(GST_LIBS)
+CFLAGS += $(GST_CFLAGS)
diff --git a/testsuite/refcounting/bin.c b/testsuite/refcounting/bin.c
new file mode 100644
index 000000000..16c7eb15d
--- /dev/null
+++ b/testsuite/refcounting/bin.c
@@ -0,0 +1,272 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_bin (void)
+{
+ GstElement *bin;
+ GstElement *element;
+
+ bin = gst_bin_new ("testbin");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ gst_bin_add (GST_BIN (bin), element);
+ element = gst_element_new ();
+ gst_element_set_name (element, "test2");
+ gst_bin_add (GST_BIN (bin), element);
+
+ return bin;
+}
+
+static GstElement*
+create_bin_ghostpads (void)
+{
+ GstElement *bin;
+ GstElement *element1, *element2;
+
+ bin = gst_bin_new ("testbin");
+ element1 = gst_element_new ();
+ gst_element_set_name (element1, "test1");
+ gst_element_add_pad (element1, gst_pad_new ("src1", GST_PAD_SRC));
+ gst_bin_add (GST_BIN (bin), element1);
+ element2 = gst_element_new ();
+ gst_element_set_name (element2, "test2");
+ gst_element_add_pad (element2, gst_pad_new ("sink1", GST_PAD_SINK));
+ gst_bin_add (GST_BIN (bin), element2);
+ gst_element_connect (element1, "src1", element2, "sink1");
+ gst_element_add_ghost_pad (bin, gst_element_get_pad (element2, "sink1"), "ghost_sink");
+
+ return bin;
+}
+
+static void
+add_remove_test1 (void)
+{
+ GstElement *bin;
+ GstElement *element;
+
+ bin = gst_bin_new ("testbin");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (bin), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ gst_bin_remove (GST_BIN (bin), element);
+
+ gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test2 (void)
+{
+ GstElement *bin;
+ GstElement *element;
+
+ bin = gst_bin_new ("testbin");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ gst_object_ref (GST_OBJECT (element));
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (bin), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ gst_bin_remove (GST_BIN (bin), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ g_assert (!GST_OBJECT_DESTROYED (element));
+
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (GST_OBJECT_DESTROYED (element));
+ gst_object_unref (GST_OBJECT (element));
+
+ gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test3 (void)
+{
+ GstElement *bin;
+ GstElement *element;
+
+ bin = gst_bin_new ("testbin");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (bin), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
+
+ gst_object_unref (GST_OBJECT (bin));
+}
+
+static void
+add_remove_test4 (void)
+{
+ GstElement *bin, *bin2;
+ GstElement *element;
+
+ bin = gst_bin_new ("testbin");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (bin), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+
+ bin2 = create_bin ();
+ g_assert (GST_OBJECT_FLOATING (bin2));
+ gst_bin_add (GST_BIN (bin), bin2);
+ g_assert (!GST_OBJECT_FLOATING (bin2));
+
+ gst_object_destroy (GST_OBJECT (bin2));
+ g_assert (gst_bin_get_by_name (GST_BIN (bin), "testbin") == NULL);
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
+
+ gst_object_unref (GST_OBJECT (bin));
+}
+
+int
+main (int argc, gchar *argv[])
+{
+ GstElement *bin;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+ g_print ("starting test\n");
+ usage1 = vmsize();
+
+ bin = gst_bin_new ("somebin");
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("create/unref new bin %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+ bin = gst_bin_new ("somebin");
+ g_assert (GST_OBJECT_FLOATING (bin));
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_sink (GST_OBJECT (bin));
+ g_assert (!GST_OBJECT_FLOATING (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("create/ref/sink/unref new bin %ld\n", vmsize()-usage1);
+
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_sink (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/ref/sink/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+ bin = gst_bin_new ("somebin");
+ g_assert (!GST_OBJECT_DESTROYED (bin));
+ gst_object_destroy (GST_OBJECT (bin));
+ g_assert (GST_OBJECT_DESTROYED (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("create/destroy/unref new bin %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_destroy (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/destroy/unref %d bin %ld\n", iters, vmsize()-usage1);
+
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("create/ref/unref/unref new bin %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/ref/unref/unref %d bin %ld\n", iters, vmsize()-usage1);
+
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_destroy (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("craete/ref/destroy/unref/unref new bin %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_object_destroy (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d bins %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = gst_bin_new ("somebin");
+ gst_object_ref (GST_OBJECT (bin));
+ gst_element_set_name (bin, "testing123");
+ gst_object_destroy (GST_OBJECT (bin));
+ gst_element_set_name (bin, "testing123");
+ gst_object_unref (GST_OBJECT (bin));
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d bins with name %ld\n", iters, vmsize()-usage1);
+
+ bin = gst_bin_new ("somebin");
+ for (i=0; i<iters;i++) {
+ gst_element_set_name (bin, "testing");
+ }
+ gst_object_unref (GST_OBJECT (bin));
+ g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ bin = create_bin();
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/unref %d bin with children %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters/2;i++) {
+ bin = create_bin_ghostpads();
+ gst_object_unref (GST_OBJECT (bin));
+ }
+ g_print ("create/unref %d bin with children and ghostpads %ld\n", iters/2, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test1();
+ }
+ g_print ("add/remove test1 %d in bin %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test2();
+ }
+ g_print ("add/remove test2 %d in bin %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test3();
+ }
+ g_print ("add/destroy/remove test3 %d in bin %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test4();
+ }
+ g_print ("add/destroy/remove test4 %d in bin %ld\n", iters, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/testsuite/refcounting/element.c b/testsuite/refcounting/element.c
new file mode 100644
index 000000000..f61ffbcd4
--- /dev/null
+++ b/testsuite/refcounting/element.c
@@ -0,0 +1,116 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+ GstElement *element;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+ g_print ("starting test\n");
+ usage1 = vmsize();
+
+ element = gst_element_new ();
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("create/unref new element %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+ element = gst_element_new ();
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_sink (GST_OBJECT (element));
+ g_assert (!GST_OBJECT_FLOATING (element));
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("create/ref/sink/unref new element %ld\n", vmsize()-usage1);
+
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_sink (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/ref/sink/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+ element = gst_element_new ();
+ g_assert (!GST_OBJECT_DESTROYED (element));
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (GST_OBJECT_DESTROYED (element));
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("create/destroy/unref new element %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_destroy (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/destroy/unref %d element %ld\n", iters, vmsize()-usage1);
+
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("create/ref/unref/unref new element %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/ref/unref/unref %d element %ld\n", iters, vmsize()-usage1);
+
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_destroy (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("craete/ref/destroy/unref/unref new element %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_object_destroy (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ element = gst_element_new ();
+ gst_object_ref (GST_OBJECT (element));
+ gst_element_set_name (element, "testing123");
+ gst_object_destroy (GST_OBJECT (element));
+ gst_element_set_name (element, "testing123");
+ gst_object_unref (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d elements with name %ld\n", iters, vmsize()-usage1);
+
+ element = gst_element_new ();
+ for (i=0; i<iters;i++) {
+ gst_element_set_name (element, "testing");
+ }
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/testsuite/refcounting/element_pad.c b/testsuite/refcounting/element_pad.c
new file mode 100644
index 000000000..0f80291d6
--- /dev/null
+++ b/testsuite/refcounting/element_pad.c
@@ -0,0 +1,134 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_element (gchar *padname, GstPadDirection dir)
+{
+ GstElement *element;
+ GstPad *pad;
+
+ element = gst_element_new ();
+ pad = gst_pad_new (padname, dir);
+ gst_element_add_pad (element, pad);
+
+ return element;
+}
+
+int
+main (int argc, gchar *argv[])
+{
+ GstElement *element;
+ GstElement *element2;
+ GstPad *pad;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+
+ g_print ("starting element with pad test with %d iterations\n", iters);
+ usage1 = vmsize();
+
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ g_assert (GST_OBJECT_FLOATING (element));
+ g_assert (!GST_OBJECT_FLOATING (pad));
+ g_assert (gst_pad_get_parent (pad) == element);
+ gst_object_unref (GST_OBJECT (element));
+ g_print ("create/addpad/unref new element %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/addpad/unref %d elements %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ element2 = create_element ("src", GST_PAD_SRC);
+ gst_element_connect (element, "sink", element2, "src");
+ g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+ g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element, "sink")));
+ gst_object_unref (GST_OBJECT (element));
+ g_assert (!GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+ gst_object_unref (GST_OBJECT (element2));
+ }
+ g_print ("create/connect/unref %d elements %ld\n", iters/2, vmsize()-usage1);
+
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ element2 = create_element ("src", GST_PAD_SRC);
+ gst_element_connect (element, "sink", element2, "src");
+ g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+ g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element, "sink")));
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (GST_OBJECT_DESTROYED (element));
+ g_assert (!GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
+ gst_object_unref (GST_OBJECT (element2));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("create/connect/destroy %d elements %ld\n", iters/2, vmsize()-usage1);
+
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_element_remove_pad (element, pad);
+ g_assert (gst_element_get_pad (element, "sink") == NULL);
+
+ g_print ("pad removal ok %ld\n", vmsize()-usage1);
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_element_remove_pad (element, pad);
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("pad removal loop %d %ld\n", iters/2, vmsize()-usage1);
+
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_object_ref (GST_OBJECT (pad));
+ gst_element_remove_pad (element, pad);
+ g_assert (gst_pad_get_parent (pad) == NULL);
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("pad removal and test loop %d %ld\n", iters/2, vmsize()-usage1);
+
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (GST_OBJECT_DESTROYED (element));
+ g_assert (gst_element_get_pad (element, "sink") == NULL);
+ gst_object_unref (GST_OBJECT (element));
+
+ g_print ("pad destroy/removal ok %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_object_destroy (GST_OBJECT (element));
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("pad destroy/removal loop %d %ld\n", iters/2, vmsize()-usage1);
+
+ for (i=0; i<iters/2; i++) {
+ element = create_element ("sink", GST_PAD_SINK);
+ pad = gst_element_get_pad (element, "sink");
+ gst_object_destroy (GST_OBJECT (pad));
+ g_assert (gst_element_get_pad (element, "sink") == NULL);
+ gst_object_unref (GST_OBJECT (element));
+ }
+ g_print ("pad destroy loop %d %ld\n", iters/2, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/testsuite/refcounting/mem.c b/testsuite/refcounting/mem.c
new file mode 100644
index 000000000..8e1c573bd
--- /dev/null
+++ b/testsuite/refcounting/mem.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int vmsize() {
+ int pid,fd,size,i,mem;
+ char filename[17], buf[256], *ptr, *end;
+
+ pid = getpid();
+ snprintf(filename,17,"/proc/%d/stat",pid);
+ fd = open(filename,O_RDONLY);
+ size = read(fd,buf,240);
+ ptr = buf;
+ for (i=0;i<22;i++)
+ ptr = (char *)strchr(ptr,' ') + 1;
+ end = (char *)strchr(ptr,' ');
+ *end = 0;
+ sscanf(ptr,"%d",&mem);
+ close(fd);
+ return mem;
+}
diff --git a/testsuite/refcounting/mem.h b/testsuite/refcounting/mem.h
new file mode 100644
index 000000000..28999db2c
--- /dev/null
+++ b/testsuite/refcounting/mem.h
@@ -0,0 +1 @@
+int vmsize();
diff --git a/testsuite/refcounting/object.c b/testsuite/refcounting/object.c
new file mode 100644
index 000000000..477ec9b5d
--- /dev/null
+++ b/testsuite/refcounting/object.c
@@ -0,0 +1,156 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+ GstObject *object, *object2;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+ g_print ("starting test with %d iterations\n", iters);
+ usage1 = vmsize();
+ object = gst_object_new ();
+ gst_object_unref (object);
+ g_print ("create/unref new object %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_unref (object);
+
+ }
+ g_print ("create/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ g_assert (GST_OBJECT_FLOATING (object));
+ gst_object_ref (object);
+ gst_object_sink (object);
+ g_assert (!GST_OBJECT_FLOATING (object));
+ gst_object_unref (object);
+ g_print ("create/ref/sink/unref new object %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_sink (object);
+ gst_object_unref (object);
+ }
+ g_print ("create/ref/sink/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ g_assert (!GST_OBJECT_DESTROYED (object));
+ gst_object_destroy (object);
+ g_assert (GST_OBJECT_DESTROYED (object));
+ gst_object_unref (object);
+ g_print ("create/destroy/unref new object %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_destroy (object);
+ gst_object_unref (object);
+ }
+ g_print ("destroy/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_unref (object);
+ gst_object_unref (object);
+ g_print ("create/ref/unref/unref new object %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_unref (object);
+ gst_object_unref (object);
+ }
+ g_print ("create/ref/unref/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_destroy (object);
+ gst_object_unref (object);
+ gst_object_unref (object);
+ g_print ("create/ref/destroy/unref/unref new object %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_destroy (object);
+ gst_object_unref (object);
+ gst_object_unref (object);
+ }
+ g_print ("create/ref/destroy/unref/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ gst_object_ref (object);
+ gst_object_set_name (object, "testing123");
+ gst_object_destroy (object);
+ gst_object_set_name (object, "testing123");
+ gst_object_unref (object);
+ gst_object_unref (object);
+ }
+ g_print ("create/ref/destroy/unref/unref %d object with name %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ for (i=0; i<iters;i++) {
+ gst_object_set_name (object, "testing");
+ }
+ gst_object_unref (object);
+ g_print ("create/set name/unref %d object %ld\n", iters, vmsize()-usage1);
+
+ object = gst_object_new ();
+ object2 = gst_object_new ();
+ g_assert (GST_OBJECT_FLOATING (object));
+ g_assert (GST_OBJECT_FLOATING (object2));
+
+ gst_object_set_parent (object, object2);
+ g_assert (GST_OBJECT_FLOATING (object2));
+ g_assert (!GST_OBJECT_FLOATING (object));
+
+ g_print ("parentage flags set_parent ok %ld\n", vmsize()-usage1);
+
+ gst_object_ref (object);
+ gst_object_unparent (object);
+ g_assert (GST_OBJECT_FLOATING (object2));
+ g_assert (!GST_OBJECT_FLOATING (object));
+ g_assert (gst_object_get_parent (object) == NULL);
+
+ g_print ("parentage flags unparent ok %ld\n", vmsize()-usage1);
+
+ gst_object_set_parent (object, object2);
+ g_assert (GST_OBJECT_FLOATING (object2));
+ g_assert (!GST_OBJECT_FLOATING (object));
+ g_assert (gst_object_get_parent (object) == object2);
+
+ gst_object_destroy (object);
+ g_assert (GST_OBJECT_DESTROYED (object));
+ g_assert (!GST_OBJECT_FLOATING (object));
+ g_assert (gst_object_get_parent (object) == NULL);
+ gst_object_unref (object);
+
+ g_print ("parentage flags destroy ok %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ object = gst_object_new ();
+ object2 = gst_object_new ();
+ gst_object_set_parent (object2, object);
+ gst_object_unref (object);
+ gst_object_unref (object2);
+ }
+ g_print ("create/unref %d 2 parented objects %ld\n", iters, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/testsuite/refcounting/pad.c b/testsuite/refcounting/pad.c
new file mode 100644
index 000000000..fed2554cb
--- /dev/null
+++ b/testsuite/refcounting/pad.c
@@ -0,0 +1,223 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+int
+main (int argc, gchar *argv[])
+{
+ GstPad *pad;
+ GstPad *pad2;
+ GstPadTemplate *padtempl;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+ g_print ("starting pad test\n");
+ usage1 = vmsize();
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("create/unref new pad %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ g_assert (GST_OBJECT_FLOATING (pad));
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_sink (GST_OBJECT (pad));
+ g_assert (!GST_OBJECT_FLOATING (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("create/ref/sink/unref new pad %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_sink (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/ref/sink/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ g_assert (!GST_OBJECT_DESTROYED (pad));
+ gst_object_destroy (GST_OBJECT (pad));
+ g_assert (GST_OBJECT_DESTROYED (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("create/destroy/unref pad %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_destroy (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/destroy/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("create/ref/unref/unref pad %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/ref/unref/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_destroy (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("create/ref/destroy/unref/unref pad %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_object_destroy (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/ref/destroy/unref/unref %d pads %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ gst_object_ref (GST_OBJECT (pad));
+ gst_pad_set_name (pad, "testing123");
+ gst_object_destroy (GST_OBJECT (pad));
+ gst_pad_set_name (pad, "testing123");
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("create/ref/destroy/unref/unref %d pads %ld with name\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ for (i=0; i<iters;i++) {
+ gst_pad_set_name (pad, "testing");
+ }
+ gst_object_unref (GST_OBJECT (pad));
+ g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+ gst_pad_connect (pad2, pad);
+ g_assert (GST_PAD_CONNECTED (pad));
+ g_assert (GST_PAD_CONNECTED (pad2));
+ gst_pad_disconnect (pad2, pad);
+ g_assert (!GST_PAD_CONNECTED (pad));
+ g_assert (!GST_PAD_CONNECTED (pad2));
+ g_print ("connect/disconnect pad %ld\n", vmsize()-usage1);
+ gst_pad_connect (pad, pad2);
+ g_assert (GST_PAD_CONNECTED (pad));
+ g_assert (GST_PAD_CONNECTED (pad2));
+ gst_pad_disconnect (pad, pad2);
+ g_assert (!GST_PAD_CONNECTED (pad));
+ g_assert (!GST_PAD_CONNECTED (pad2));
+ g_print ("connect/disconnect pad wrong direction %ld\n", vmsize()-usage1);
+
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad2));
+
+ for (i=0; i<iters;i++) {
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+ gst_pad_connect (pad2, pad);
+ gst_pad_disconnect (pad2, pad);
+ gst_pad_connect (pad, pad2);
+ gst_pad_disconnect (pad, pad2);
+ gst_object_unref (GST_OBJECT (pad));
+ gst_object_unref (GST_OBJECT (pad2));
+ }
+ g_print ("connect/disconnect %d pads %ld\n", iters, vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+ gst_pad_connect (pad2, pad);
+ g_assert (GST_PAD_CONNECTED (pad2));
+ g_assert (GST_PAD_CONNECTED (pad));
+
+ gst_object_unref (GST_OBJECT (pad2));
+ g_assert (!GST_PAD_CONNECTED (pad));
+ g_assert (!GST_OBJECT_DESTROYED (pad));
+ gst_object_unref (GST_OBJECT (pad));
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+ gst_pad_connect (pad2, pad);
+ g_assert (GST_PAD_CONNECTED (pad2));
+ g_assert (GST_PAD_CONNECTED (pad));
+
+ gst_object_unref (GST_OBJECT (pad));
+ g_assert (!GST_PAD_CONNECTED (pad2));
+ g_assert (!GST_OBJECT_DESTROYED (pad2));
+ gst_object_unref (GST_OBJECT (pad2));
+
+ g_print ("pad unref effects on connect pad ok %ld\n", vmsize()-usage1);
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+ gst_pad_connect (pad2, pad);
+ g_assert (GST_PAD_CONNECTED (pad2));
+ g_assert (GST_PAD_CONNECTED (pad));
+
+ gst_object_destroy (GST_OBJECT (pad2));
+ g_assert (GST_OBJECT_DESTROYED (pad2));
+ g_assert (!GST_OBJECT_DESTROYED (pad));
+ g_assert (!GST_PAD_CONNECTED (pad));
+ gst_object_unref (GST_OBJECT (pad2));
+ g_assert (!GST_OBJECT_DESTROYED (pad));
+ g_assert (!GST_PAD_CONNECTED (pad));
+ gst_object_unref (GST_OBJECT (pad));
+
+ pad = gst_pad_new ("padname", GST_PAD_SINK);
+ pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
+
+ gst_pad_connect (pad2, pad);
+ g_assert (GST_PAD_CONNECTED (pad2));
+ g_assert (GST_PAD_CONNECTED (pad));
+
+ gst_object_destroy (GST_OBJECT (pad));
+ g_assert (GST_OBJECT_DESTROYED (pad));
+ g_assert (!GST_OBJECT_DESTROYED (pad2));
+ g_assert (!GST_PAD_CONNECTED (pad2));
+ gst_object_unref (GST_OBJECT (pad));
+ g_assert (!GST_OBJECT_DESTROYED (pad2));
+ g_assert (!GST_PAD_CONNECTED (pad2));
+ gst_object_unref (GST_OBJECT (pad2));
+
+ g_print ("pad destroy effects on connect pad ok %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ padtempl = gst_padtemplate_new ("sink%d", GST_PAD_SINK, GST_PAD_SOMETIMES, NULL);
+ gst_object_unref (GST_OBJECT (padtempl));
+ }
+ g_print ("%d padtemplates create/unref %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ padtempl = gst_padtemplate_new ("sink%d", GST_PAD_SINK, GST_PAD_SOMETIMES, NULL);
+ pad = gst_pad_new_from_template (padtempl, "sink1");
+ gst_object_unref (GST_OBJECT (pad));
+ }
+ g_print ("%d pads create/unref from padtemplate %ld\n", iters, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return vmsize()-usage1;
+}
diff --git a/testsuite/refcounting/thread.c b/testsuite/refcounting/thread.c
new file mode 100644
index 000000000..f229a54c6
--- /dev/null
+++ b/testsuite/refcounting/thread.c
@@ -0,0 +1,281 @@
+#include <gst/gst.h>
+
+#define ITERS 100000
+#include <stdlib.h>
+#include "mem.h"
+
+static GstElement*
+create_thread (void)
+{
+ GstElement *thread;
+ GstElement *element;
+
+ thread = gst_thread_new ("testthread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ gst_bin_add (GST_BIN (thread), element);
+ element = gst_element_new ();
+ gst_element_set_name (element, "test2");
+ gst_bin_add (GST_BIN (thread), element);
+
+ return thread;
+}
+
+static GstElement*
+create_thread_ghostpads (void)
+{
+ GstElement *thread;
+ GstElement *element1, *element2;
+
+ thread = gst_thread_new ("testthread");
+ element1 = gst_element_new ();
+ gst_element_set_name (element1, "test1");
+ gst_element_add_pad (element1, gst_pad_new ("src1", GST_PAD_SRC));
+ gst_bin_add (GST_BIN (thread), element1);
+ element2 = gst_element_new ();
+ gst_element_set_name (element2, "test2");
+ gst_element_add_pad (element2, gst_pad_new ("sink1", GST_PAD_SINK));
+ gst_bin_add (GST_BIN (thread), element2);
+ gst_element_connect (element1, "src1", element2, "sink1");
+ gst_element_add_ghost_pad (thread, gst_element_get_pad (element2, "sink1"), "sink1");
+
+ return thread;
+}
+
+static void
+add_remove_test1 (void)
+{
+ GstElement *thread;
+ GstElement *element;
+
+ thread = gst_thread_new ("testthread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (thread), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ gst_bin_remove (GST_BIN (thread), element);
+
+ gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test2 (void)
+{
+ GstElement *thread;
+ GstElement *element;
+
+ thread = gst_thread_new ("testthread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ gst_object_ref (GST_OBJECT (element));
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (thread), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ gst_bin_remove (GST_BIN (thread), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+ g_assert (!GST_OBJECT_DESTROYED (element));
+
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (GST_OBJECT_DESTROYED (element));
+ gst_object_unref (GST_OBJECT (element));
+
+ gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test3 (void)
+{
+ GstElement *thread;
+ GstElement *element;
+
+ thread = gst_thread_new ("testthread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (thread), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (gst_bin_get_by_name (GST_BIN (thread), "test1") == NULL);
+
+ gst_object_unref (GST_OBJECT (thread));
+}
+
+static void
+add_remove_test4 (void)
+{
+ GstElement *thread, *thread2;
+ GstElement *element;
+
+ thread = gst_thread_new ("testthread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ g_assert (GST_OBJECT_FLOATING (element));
+ gst_bin_add (GST_BIN (thread), element);
+ g_assert (!GST_OBJECT_FLOATING (element));
+
+ thread2 = create_thread ();
+ g_assert (GST_OBJECT_FLOATING (thread2));
+ gst_bin_add (GST_BIN (thread), thread2);
+ g_assert (!GST_OBJECT_FLOATING (thread2));
+
+ gst_object_destroy (GST_OBJECT (thread2));
+ g_assert (gst_bin_get_by_name (GST_BIN (thread), "testthread") == NULL);
+ gst_object_destroy (GST_OBJECT (element));
+ g_assert (gst_bin_get_by_name (GST_BIN (thread), "test1") == NULL);
+
+ gst_object_unref (GST_OBJECT (thread));
+}
+
+int
+main (int argc, gchar *argv[])
+{
+ GstElement *thread, *element;
+ long usage1;
+ gint i, iters;
+
+ gst_init (&argc, &argv);
+
+ if (argc == 2)
+ iters = atoi (argv[1]);
+ else
+ iters = ITERS;
+
+ g_print ("starting test\n");
+ usage1 = vmsize();
+
+ thread = gst_thread_new ("somethread");
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("create/unref new thread %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+ thread = gst_thread_new ("somethread");
+ g_assert (GST_OBJECT_FLOATING (thread));
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_sink (GST_OBJECT (thread));
+ g_assert (!GST_OBJECT_FLOATING (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("create/ref/sink/unref new thread %ld\n", vmsize()-usage1);
+
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_sink (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/ref/sink/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+ thread = gst_thread_new ("somethread");
+ g_assert (!GST_OBJECT_DESTROYED (thread));
+ gst_object_destroy (GST_OBJECT (thread));
+ g_assert (GST_OBJECT_DESTROYED (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("create/destroy/unref new thread %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_destroy (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/destroy/unref %d thread %ld\n", iters, vmsize()-usage1);
+
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("create/ref/unref/unref new thread %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/ref/unref/unref %d thread %ld\n", iters, vmsize()-usage1);
+
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_destroy (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("craete/ref/destroy/unref/unref new thread %ld\n", vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_object_destroy (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d threads %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ gst_object_ref (GST_OBJECT (thread));
+ gst_element_set_name (thread, "testing123");
+ gst_object_destroy (GST_OBJECT (thread));
+ gst_element_set_name (thread, "testing123");
+ gst_object_unref (GST_OBJECT (thread));
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("craete/ref/destroy/unref/unref %d threads with name %ld\n", iters, vmsize()-usage1);
+
+ thread = gst_thread_new ("somethread");
+ for (i=0; i<iters;i++) {
+ gst_element_set_name (thread, "testing");
+ }
+ gst_object_unref (GST_OBJECT (thread));
+ g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = gst_thread_new ("somethread");
+ element = gst_element_new ();
+ gst_element_set_name (element, "test1");
+ gst_bin_add (GST_BIN (thread), element);
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/unref %d thread with one element %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ thread = create_thread();
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/unref %d thread with children %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters/2;i++) {
+ thread = create_thread_ghostpads();
+ gst_object_unref (GST_OBJECT (thread));
+ }
+ g_print ("create/unref %d thread with children and ghostpads %ld\n", iters/2, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test1();
+ }
+ g_print ("add/remove test1 %d in thread %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test2();
+ }
+ g_print ("add/remove test2 %d in thread %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test3();
+ }
+ g_print ("add/destroy/remove test3 %d in thread %ld\n", iters, vmsize()-usage1);
+
+ for (i=0; i<iters;i++) {
+ add_remove_test4();
+ }
+ g_print ("add/destroy/remove test4 %d in thread %ld\n", iters, vmsize()-usage1);
+
+ g_print ("leaked: %ld\n", vmsize()-usage1);
+
+ return (vmsize()-usage1 ? -1 : 0);
+}
diff --git a/tools/.gitignore b/tools/.gitignore
index e5db16aaa..beeec25e2 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -9,4 +9,6 @@ Makefile.in
gstreamer-launch
gstreamer-register
gstreamer-inspect
+gstreamer-compprep
+gstreamer-complete
*.xml
diff --git a/tools/Makefile.am b/tools/Makefile.am
index f723d5d02..e0bbeeb16 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,4 +1,5 @@
-bin_PROGRAMS = gstreamer-launch gstreamer-register gstreamer-inspect
+bin_PROGRAMS = gstreamer-launch gstreamer-register gstreamer-inspect \
+ gstreamer-compprep gstreamer-complete
man_MANS = gstreamer-launch.1 gstreamer-register.1 gstreamer-inspect.1
diff --git a/tools/gstreamer-complete.c b/tools/gstreamer-complete.c
new file mode 100644
index 000000000..aaf70ace9
--- /dev/null
+++ b/tools/gstreamer-complete.c
@@ -0,0 +1,203 @@
+#include <stdio.h>
+#include <string.h>
+#include <parser.h>
+#include <glib.h>
+
+#include "config.h"
+
+typedef struct {
+ gchar *name;
+ GSList *srcpads;
+ GSList *sinkpads;
+ GSList *srcpadtemplates;
+ GSList *sinkpadtemplates;
+ GSList *arguments;
+} comp_element;
+
+enum {
+ ARG_INT,
+ ARG_FILENAME,
+ ARG_ENUM
+};
+
+typedef struct {
+ gchar *name;
+ int type;
+ GSList *enums;
+} comp_argument;
+
+typedef struct {
+ gint value;
+ gchar *nick;
+} enum_value;
+
+
+void print_match_list (gchar *prefix, int len, GSList *wordlist) {
+ GSList *words = wordlist;
+
+ while (words) {
+ if (!len || !strncmp((gchar *)(words->data), prefix, len))
+ printf("%s\n",(gchar *)(words->data));
+ words = g_slist_next (words);
+ }
+}
+
+int match_element (comp_element *element, gchar *name) {
+ return strcmp(element->name,name);
+}
+
+int main(int argc,char *argv[]) {
+ xmlDocPtr doc;
+ xmlNodePtr rootnode, elementnode, propnode, argnode;
+ GList *element_list = NULL;
+ comp_element *element;
+ GSList *element_names = NULL;
+ comp_argument *argument;
+ enum_value *option;
+
+ gchar *prev_word = argv[3];
+ gchar *partial_word = argv[2];
+ int partial_len = strlen(partial_word);
+ GList *elements;
+ GSList *pads;
+ int num_pads;
+ GSList *args;
+ gchar *word;
+ GSList *words = NULL;
+
+ /***** Loading the completion information from the registry *****/
+
+ doc = xmlParseFile (GST_CONFIG_DIR "/compreg.xml");
+ rootnode = doc->xmlRootNode;
+
+ elementnode = rootnode->xmlChildrenNode;
+ while (elementnode) {
+ if (!strcmp(elementnode->name, "element")) {
+ element = g_new0(comp_element,1);
+ propnode = elementnode->xmlChildrenNode;
+ while (propnode) {
+
+ if (!strcmp(propnode->name, "name")) {
+ element->name = xmlNodeGetContent(propnode);
+//fprintf(stderr,element->name);
+ } else if (!strcmp(propnode->name, "srcpad")) {
+ element->srcpads = g_slist_prepend(element->srcpads, xmlNodeGetContent(propnode));
+//fprintf(stderr,".");
+ } else if (!strcmp(propnode->name, "sinkpad")) {
+ element->sinkpads = g_slist_prepend(element->sinkpads, xmlNodeGetContent(propnode));
+ } else if (!strcmp(propnode->name, "srcpadtemplate")) {
+ element->srcpadtemplates = g_slist_prepend(element->srcpadtemplates, xmlNodeGetContent(propnode));
+//fprintf(stderr,".");
+ } else if (!strcmp(propnode->name, "sinkpad")) {
+ element->sinkpadtemplates = g_slist_prepend(element->sinkpadtemplates, xmlNodeGetContent(propnode));
+ } else if (!strcmp(propnode->name, "argument")) {
+ argument = g_new0(comp_argument,1);
+ argument->name = xmlNodeGetContent(propnode);
+ argument->type = ARG_INT;
+
+ // walk through the values data
+ argnode = propnode->xmlChildrenNode;
+ while (argnode) {
+ if (!strcmp(argnode->name, "filename")) {
+ argument->type = ARG_FILENAME;
+ } else if (!strcmp(argnode->name,"option")) {
+ argument->type = ARG_ENUM;
+ option = g_new0(enum_value,1);
+ sscanf(xmlNodeGetContent(argnode),"%d",&option->value);
+ argument->enums = g_slist_prepend (argument->enums, option);
+ }
+ argnode = argnode->next;
+ }
+
+ element->arguments = g_slist_prepend(element->arguments, argument);
+ }
+
+ propnode = propnode->next;
+ }
+ element_list = g_list_prepend(element_list, element);
+ element_names = g_slist_prepend(element_names, element->name);
+ }
+ elementnode = elementnode->next;
+ }
+
+
+
+ /***** Completion *****/
+
+ /* The bulk of the work is in deciding exactly which words are an option. */
+
+ // if we're right at the beginning, with -launch in the first word
+ if (strstr(prev_word,"-launch")) {
+ // print out only elements with no sink pad or padtemplate
+ elements = element_list;
+ while (elements) {
+ element = (comp_element *)(elements->data);
+ if (!element->sinkpads && !element->sinkpadtemplates)
+ words = g_slist_prepend (words, element->name);
+ elements = g_list_next(elements);
+ }
+ }
+
+ // if the previous word is a connection
+ if (strchr(prev_word, '!')) {
+ // print out oly elements with a sink pad or template
+ elements = element_list;
+ while (elements) {
+ element = (comp_element *)(elements->data);
+ if (element->sinkpads || element->sinkpadtemplates)
+ words = g_slist_prepend (words, element->name);
+ elements = g_list_next (elements);
+ }
+ }
+
+ // if the partial word is an argument, and it's an enum
+ if (strchr(prev_word,'=')) {
+ fprintf(stderr,"it's an arg, but dunno what element yet\n");
+ }
+
+ // if the previous word is an element, we need to list both pads and arguments
+ if ((elements = g_list_find_custom(element_list, prev_word, (GCompareFunc)match_element))) {
+ element = elements->data;
+ // zero the numpads list so we can count them
+ num_pads = 0;
+
+ // pads
+ pads = element->srcpads;
+ while (pads) {
+ num_pads++;
+ words = g_slist_prepend (words, g_strdup_printf("%s!",(gchar *)(pads->data)));
+ pads = g_slist_next (pads);
+ }
+
+ // padtemplates
+ pads = element->srcpadtemplates;
+ while (pads) {
+ num_pads++;
+ word = g_strdup_printf("%s!",(gchar *)(pads->data));
+ if (!g_slist_find_custom(words,word,(GCompareFunc)strcmp))
+ words = g_slist_prepend (words, word);
+ pads = g_slist_next (pads);
+ }
+
+ // if there is only one pad, add '!' to the list of completions
+ if (num_pads == 1) {
+ words = g_slist_prepend (words, "!");
+ }
+
+ // arguments
+ args = element->arguments;
+ while (args) {
+ argument = (comp_argument *)(args->data);
+ word = strstr(argument->name,"::")+2;
+ words = g_slist_prepend (words, g_strdup_printf("%s=",word));
+ words = g_slist_prepend (words, g_strdup_printf("%s=...",word));
+ args = g_slist_next (args);
+ }
+ }
+
+
+ /* The easy part is ouptuting the correct list of possibilities. */
+ print_match_list (partial_word, partial_len, words);
+
+ return 0;
+}
diff --git a/tools/gstreamer-compprep.c b/tools/gstreamer-compprep.c
new file mode 100644
index 000000000..c0c3e3afd
--- /dev/null
+++ b/tools/gstreamer-compprep.c
@@ -0,0 +1,91 @@
+#include <gst/gst.h>
+#include "config.h"
+
+int main(int argc,char *argv[]) {
+ xmlDocPtr doc;
+ xmlNodePtr factorynode, padnode, argnode, optionnode;
+ GList *plugins, *factories, *padtemplates, *pads;
+ GstPlugin *plugin;
+ GstElementFactory *factory;
+ GstElement *element;
+ GstPad *pad;
+ GstPadTemplate *padtemplate;
+ GtkArg *args;
+ guint32 *flags;
+ gint num_args,i;
+
+ gst_debug_set_categories(0);
+ gst_info_set_categories(0);
+ gst_init(&argc,&argv);
+
+ doc = xmlNewDoc("1.0");
+ doc->xmlRootNode = xmlNewDocNode(doc, NULL, "GST-CompletionRegistry", NULL);
+
+ plugins = gst_plugin_get_list();
+ while (plugins) {
+ plugin = (GstPlugin *)(plugins->data);
+ plugins = g_list_next (plugins);
+
+ factories = gst_plugin_get_factory_list(plugin);
+ while (factories) {
+ factory = (GstElementFactory *)(factories->data);
+ factories = g_list_next (factories);
+
+ factorynode = xmlNewChild (doc->xmlRootNode, NULL, "element", NULL);
+ xmlNewChild (factorynode, NULL, "name", factory->name);
+
+ element = gst_elementfactory_create(factory,"element");
+ if (element == NULL) {
+ fprintf(stderr,"couldn't construct element from factory %s\n",factory->name);
+ return 1;
+ }
+
+ // write out the padtemplates
+ padtemplates = factory->padtemplates;
+ while (padtemplates) {
+ padtemplate = (GstPadTemplate *)(padtemplates->data);
+ padtemplates = g_list_next (padtemplates);
+
+ if (padtemplate->direction == GST_PAD_SRC)
+ padnode = xmlNewChild (factorynode, NULL, "srcpadtemplate", padtemplate->name_template);
+ else if (padtemplate->direction == GST_PAD_SINK)
+ padnode = xmlNewChild (factorynode, NULL, "sinkpadtemplate", padtemplate->name_template);
+ }
+
+ pads = gst_element_get_pad_list (element);
+ while (pads) {
+ pad = (GstPad *)(pads->data);
+ pads = g_list_next (pads);
+
+ if (GST_PAD_DIRECTION(pad) == GST_PAD_SRC)
+ padnode = xmlNewChild (factorynode, NULL, "srcpad", GST_PAD_NAME(pad));
+ else if (GST_PAD_DIRECTION(pad) == GST_PAD_SINK)
+ padnode = xmlNewChild (factorynode, NULL, "sinkpad", GST_PAD_NAME(pad));
+ }
+
+ // write out the args
+ args = gtk_object_query_args(GTK_OBJECT_TYPE(element), &flags, &num_args);
+ for (i=0;i<num_args;i++) {
+ argnode = xmlNewChild (factorynode, NULL, "argument", args[i].name);
+ if (args[i].type == GST_TYPE_FILENAME) {
+ xmlNewChild (argnode, NULL, "filename", NULL);
+ } else if (GTK_FUNDAMENTAL_TYPE (args[i].type) == GTK_TYPE_ENUM) {
+ GtkEnumValue *values;
+ gint j;
+
+ values = gtk_type_enum_get_values (args[i].type);
+ for (j=0;values[j].value_name;j++) {
+ gchar *value = g_strdup_printf("%d",values[j].value);
+ optionnode = xmlNewChild (argnode, NULL, "option", value);
+ xmlNewChild (optionnode, NULL, "value_nick", values[j].value_nick);
+ g_free(value);
+ }
+ }
+ }
+ }
+ }
+
+ xmlSaveFile(GST_CONFIG_DIR "/compreg.xml",doc);
+
+ return 0;
+}
diff --git a/tools/gstreamer-inspect.c b/tools/gstreamer-inspect.c
index 3c455979c..81103f523 100644
--- a/tools/gstreamer-inspect.c
+++ b/tools/gstreamer-inspect.c
@@ -83,6 +83,8 @@ print_element_info (GstElementFactory *factory)
GtkArg *args;
guint32 *flags;
gint num_args,i;
+ GList *children;
+ GstElement *child;
gboolean have_flags;
element = gst_elementfactory_create(factory,"element");
@@ -150,7 +152,7 @@ print_element_info (GstElementFactory *factory)
printf("\n");
}
} else
- printf(" none\n\n");
+ printf(" none\n");
have_flags = FALSE;
@@ -173,40 +175,45 @@ print_element_info (GstElementFactory *factory)
}
if (!have_flags)
printf(" no flags set\n");
- printf("\n");
- printf("Element Implementation:\n");
+
+ printf("\nElement Implementation:\n");
+
if (element->loopfunc)
- printf(" loopfunc()-based element\n");
+ printf(" loopfunc()-based element: %s\n",GST_DEBUG_FUNCPTR_NAME(element->loopfunc));
else
printf(" No loopfunc(), must be chain-based or not configured yet\n");
- if (gstelement_class->change_state)
- printf(" Has change_state() function\n");
- else
- printf(" No change_state() class function\n");
- if (gstobject_class->save_thyself)
- printf(" Has custom save_thyself() class function\n");
- if (gstobject_class->restore_thyself)
- printf(" Has custom restore_thyself() class function\n");
- printf("\n");
+ printf(" Has change_state() function: %s\n",
+ GST_DEBUG_FUNCPTR_NAME(gstelement_class->change_state));
+ printf(" Has custom save_thyself() function: %s\n",
+ GST_DEBUG_FUNCPTR_NAME(gstobject_class->save_thyself));
+ printf(" Has custom restore_thyself() function: %s\n",
+ GST_DEBUG_FUNCPTR_NAME(gstobject_class->restore_thyself));
- printf("Pads:\n");
+
+
+ printf("\nPads:\n");
if (element->numpads) {
pads = gst_element_get_pad_list(element);
while (pads) {
pad = GST_PAD(pads->data);
pads = g_list_next(pads);
- realpad = GST_REAL_PAD(pad);
+ realpad = GST_PAD_REALIZE(pad);
if (gst_pad_get_direction(pad) == GST_PAD_SRC)
- printf(" SRC: '%s'\n",gst_pad_get_name(pad));
+ printf(" SRC: '%s'",gst_pad_get_name(pad));
else if (gst_pad_get_direction(pad) == GST_PAD_SINK)
- printf(" SINK: '%s'\n",gst_pad_get_name(pad));
+ printf(" SINK: '%s'",gst_pad_get_name(pad));
else
printf(" UNKNOWN!!!: '%s'\n",gst_pad_get_name(pad));
+ if (GST_IS_GHOST_PAD(pad))
+ printf(", ghost of real pad %s:%s\n",GST_DEBUG_PAD_NAME(realpad));
+ else
+ printf("\n");
+
printf(" Implementation:\n");
if (realpad->chainfunc)
printf(" Has chainfunc(): %s\n",GST_DEBUG_FUNCPTR_NAME(realpad->chainfunc));
@@ -216,7 +223,7 @@ print_element_info (GstElementFactory *factory)
printf(" Has getregionfunc(): %s\n",GST_DEBUG_FUNCPTR_NAME(realpad->getregionfunc));
if (realpad->qosfunc)
printf(" Has qosfunc(): %s\n",GST_DEBUG_FUNCPTR_NAME(realpad->qosfunc));
- if (realpad->eosfunc) {
+ if (realpad->eosfunc != gst_pad_eos_func) {
printf(" Has eosfunc(): %s\n",GST_DEBUG_FUNCPTR_NAME(realpad->eosfunc));
}
@@ -243,13 +250,13 @@ print_element_info (GstElementFactory *factory)
caps = caps->next;
}
}
-
- printf("\n");
}
} else
- printf(" none\n\n");
+ printf(" none\n");
+
+
- printf("Element Arguments:\n");
+ printf("\nElement Arguments:\n");
args = gtk_object_query_args(GTK_OBJECT_TYPE(element), &flags, &num_args);
for (i=0;i<num_args;i++) {
@@ -291,6 +298,20 @@ print_element_info (GstElementFactory *factory)
if (num_args == 0) g_print (" none");
printf("\n");
+
+
+ // for compound elements
+ if (GST_IS_BIN(element)) {
+ printf("\nChildren:\n");
+ children = gst_bin_get_list(GST_BIN(element));
+ while (children) {
+ child = GST_ELEMENT (children->data);
+ children = g_list_next (children);
+
+ g_print(" %s\n",GST_ELEMENT_NAME(child));
+ }
+ }
+
return 0;
}