diff --git a/configure.base b/configure.base index fc284c0740..d944188d68 100644 --- a/configure.base +++ b/configure.base @@ -42,16 +42,14 @@ AC_SUBST(GST_REVISION) AC_SUBST(GST_AGE) AC_SUBST(GST_LIBVERSION) - AM_MAINTAINER_MODE AC_PROG_CC +AM_PROG_CC_STDC +AM_PROG_AS AC_PROG_CXX AC_PROG_CXXCPP AC_ISC_POSIX -SUBSTFOR configure.ac:AC_HEADER_STDC([]) -SUBSTFOR configure.in:AC_STDC_HEADERS -AC_ARG_PROGRAM dnl We disable static building for development, for time savings dnl *NOTE*: dnl this line before release, so release does static too @@ -59,7 +57,8 @@ AM_DISABLE_STATIC AC_LIBTOOL_DLOPEN AM_PROG_LIBTOOL -CFLAGS="" +SUBSTFOR configure.ac:AC_HEADER_STDC([]) +SUBSTFOR configure.in:AC_STDC_HEADERS dnl This is used for the -config script... builddir=`pwd` @@ -193,8 +192,7 @@ int main () { return !(sizeof(off_t) == 8); } ], [ AC_MSG_RESULT(yes) -CORE_CFLAGS="$CORE_CFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" -GST_DEFINE_CFLAGS="$GST_DEFINE_CFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" +GST_CFLAGS="$GST_CFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" ], [ AC_MSG_RESULT(no) @@ -210,14 +208,13 @@ dnl Check for glib2 GST_CHECK_FEATURE(GLIB2, [use of glib-2.0 and GObject], , [ PKG_CHECK_MODULES(GLIB2, glib-2.0 gobject-2.0 gthread-2.0 gmodule-2.0, HAVE_GLIB2=yes,HAVE_GLIB2=no) - AC_SUBST(GLIB2_LIBS) - AC_SUBST(GLIB2_CFLAGS) + GLIB_LIBS=$GLIB2_LIBS + GLIB_CFLAGS=$GLIB2_CFLAGS + AC_SUBST(GLIB_LIBS) + AC_SUBST(GLIB_CFLAGS) ], disabled, [ - CORE_LIBS="$CORE_LIBS $GLIB2_LIBS" - CORE_CFLAGS="$CORE_CFLAGS $GLIB2_CFLAGS" - AC_DEFINE(USE_GLIB2) - GST_DEFINE_CFLAGS="$GST_DEFINE_CFLAGS -DUSE_GLIB2" + GST_CFLAGS="$GST_CFLAGS -DUSE_GLIB2" ]) AC_SUBST(USE_GLIB2) @@ -232,8 +229,8 @@ if test x$USE_GLIB2 = xno; then AC_MSG_ERROR(Cannot find gtk: Is gtk-config in path?)) HAVE_GTK=yes - CORE_LIBS="$CORE_LIBS $GLIB_LIBS $GTK_LIBS" - CORE_CFLAGS="$CORE_CFLAGS $GLIB_CFLAGS $GTK_CFLAGS" + GLIB_LIBS="$GLIB_LIBS $GTK_LIBS" + GLIB_CFLAGS="$GLIB_CFLAGS $GTK_CFLAGS" else GST_PKG_DEPS="glib-2.0 gobject-2.0 gmodule-2.0 gthread-2.0" @@ -257,21 +254,13 @@ AC_PATH_PROG(XML_CONFIG, xml-config, no) if test x$XML_CONFIG = xno; then AC_MSG_ERROR(Couldn't find xml-config) fi -xml_save_LIBS=$LIBS -xml_save_CFLAGS=$CFLAGS -XML_LIBS=`xml-config --libs` -XML_CFLAGS=`xml-config --cflags` -LIBS=$XML_LIBS -CFLAGS=$XML_CFLAGS -AC_CHECK_LIB(xml, xmlDocGetRootElement, , +XML_LIBS="`xml-config --libs`" +XML_CFLAGS="`xml-config --cflags`" +AC_CHECK_LIB(xml, xmlDocGetRootElement, :, [ AC_MSG_ERROR(Need version 1.8.1 or better of libxml) ], $XML_LIBS) -LIBS=$xml_save_LIBS -CFLAGS=$xml_save_CFLAGS AC_SUBST(XML_LIBS) AC_SUBST(XML_CFLAGS) -CORE_LIBS="$CORE_LIBS $XML_LIBS" -CORE_CFLAGS="$CORE_CFLAGS $XML_CFLAGS" dnl ========================================================================== @@ -317,7 +306,6 @@ dnl AC_CHECK_LIB(artsflow, convert_stereo_2float_i16le, :, HAVE_ARTS=no, $LIBS) dnl AC_CHECK_HEADER uses CPPFLAGS, but not CFLAGS. dnl FIXME: ensure only suitable flags result from artsc-config --cflags -CPPFLAGS="$CPPFLAGS $ARTS_CFLAGS" AC_CHECK_HEADER(artsflow.h, :, HAVE_ARTS=no) SUBSTFOR configure.ac:AC_LANG_POP(C++) @@ -420,17 +408,11 @@ else else LIBGLADE_GNOME_LIBS=`libglade-config --libs gnome` LIBGLADE_GNOME_CFLAGS=`libglade-config --cflags gnome` - libglade_save_CFLAGS="$CFLAGS" - libglade_save_LIBS="$LIBS" - CFLAGS="$CFLAGS $LIBGLADE_GNOME_CFLAGS $GTK_CFLAGS" - LIBS="$LIBS $LIBGLADE_GNOME_LIBS $GTK_LIBS" AC_TRY_LINK([#include ],[glade_gnome_init();], HAVE_LIBGLADE_GNOME="yes", AC_MSG_WARN( [Couldn't find gnome libraries for libglade - Can't build gstmediaplay and gsteditor]) ) - CFLAGS="$libglade_save_CFLAGS" - LIBS="$libglade_save_LIBS" fi fi AC_SUBST(LIBGLADE_GNOME_LIBS) @@ -681,29 +663,7 @@ AC_CHECK_LIB(dvdread, DVDOpen, HAVE_LIBDVDREAD=yes, HAVE_LIBDVDREAD=no, ) AC_CHECK_HEADER(dvdread/dvd_reader.h, :, HAVE_LIBDVDREAD=no) dnl Check for SDL library -AC_MSG_CHECKING(SDL library) -HAVE_LIBSDL=yes -if sdl-config --libs > /dev/null 2>&1; then - SDL_VERSION=`sdl-config --version` - AC_MSG_RESULT([found (version $SDL_VERSION)]) - SDL_LIBS="`sdl-config --libs`" - SDL_CFLAGS="`sdl-config --cflags`" - AC_CHECK_LIB(SDL, SDL_Init, :, HAVE_LIBSDL=no, $SDL_LIBS) - dnl AC_CHECK_HEADER uses CPPFLAGS, but not CFLAGS. - dnl Assume only suitable flags result from artsc-config --cflags - sdlcheck_save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $SDL_CFLAGS" - AC_CHECK_HEADER(SDL.h, :, HAVE_LIBSDL=no) - CPPFLAGS="$sdlcheck_save_CPPFLAGS" - AC_CHECK_LIB(SDL, SDL_CreateYUVOverlay, :, HAVE_LIBSDL=no, $SDL_LIBS) -else - AC_MSG_RESULT(not found) - HAVE_LIBSDL=no - SDL_LIBS= - SDL_CFLAGS= -fi -AC_SUBST(SDL_LIBS) -AC_SUBST(SDL_CFLAGS) +AM_PATH_SDL( , , HAVE_LIBSDL=no) if test "x$HAVE_LIBSDL" = "xno"; then AC_MSG_WARN( @@ -904,7 +864,7 @@ GST_SUBSYSTEM_DISABLE(PARSE,[command-line parser]) GST_SUBSYSTEM_DISABLE(TRACE,[tracing subsystem]) GST_SUBSYSTEM_DISABLE(REGISTRY,[plugin registry]) -GST_DEFINE_CFLAGS="$GST_DEFINE_CFLAGS $GST_SUBSYSTEM_DISABLE_DEFINES" +GST_CFLAGS="$GST_CFLAGS $GST_SUBSYSTEM_DISABLE_DEFINES" dnl ################################################ @@ -930,12 +890,12 @@ if test "x$PLUGINS_USE_BUILDDIR" = xyes; then AC_DEFINE(PLUGINS_USE_BUILDDIR, 1, [Define if plugins should be loaded from the build tree - only developers should use this]) fi -if test "x$USE_DEBUG" = xyes; then - CFLAGS="$CFLAGS -g" -fi +dnl if test "x$USE_DEBUG" = xyes; then +dnl CFLAGS="$CFLAGS -g" +dnl fi if test "x$USE_PROFILING" = xyes; then - CFLAGS="$CFLAGS -pg -fprofile-arcs" +dnl CFLAGS="$CFLAGS -pg -fprofile-arcs" FOMIT_FRAME_POINTER="" else FOMIT_FRAME_POINTER="-fomit-frame-pointer" @@ -1098,19 +1058,6 @@ PLUGINS_BUILDDIR=${builddir} AC_DEFINE_UNQUOTED(PLUGINS_BUILDDIR,"$PLUGINS_BUILDDIR") AC_SUBST(PLUGINS_BUILDDIR) -dnl ############################## -dnl # Set up the defaults cflags # -dnl ############################## -dnl CC="kgcc" -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) - dnl Vars for everyone else GST_LIBS="\$(top_builddir)/gst/libgst.la" GST_CFLAGS="-I\$(top_srcdir) -I\$(top_srcdir)/include" @@ -1118,30 +1065,11 @@ AC_SUBST(GST_LIBS) AC_SUBST(GST_CFLAGS) dnl Private vars for libgst only -LIBGST_LIBS="$LIBS" -LIBGST_CFLAGS="$CFLAGS $GST_CFLAGS" +LIBGST_CFLAGS="$GST_CFLAGS" AC_SUBST(LIBGST_LIBS) AC_SUBST(LIBGST_CFLAGS) -dnl CFLAGS for everyone else -CFLAGS="$GST_CFLAGS $CFLAGS" -LDFLAGS="$GST_LIBS $LDFLAGS" - -dnl Needed to make automake 1.4g happy. -dnl FIXME: find as properly, rather than just using CC -AS="\$(CC)" - -dnl Having to AC_SUBST these is messy, but doesn't seem to do any harm. -dnl I'm not sure whether it's really necessary, but it removes some warnings -dnl when automake 1.4g runs, and may be beneficial elsewhere. -AC_SUBST(LIBS) -AC_SUBST(CFLAGS) -AC_SUBST(CPPFLAGS) -AC_SUBST(LDFLAGS) -AC_SUBST(AS) -AC_SUBST(ASFLAGS) - -AC_SUBST(GST_DEFINE_CFLAGS) +AC_SUBST(GST_CFLAGS) dnl ############################# dnl # Configure the subpackages # @@ -1173,6 +1101,9 @@ dnl ######################### dnl # Make the output files # dnl ######################### +dnl until ffmpeg is handled by configure plugins/ffmpeg/Makefile +dnl components/bonobo-gstmediaplay/Makefile +dnl someone should fix this test/misc/Makefile SUBSTFOR configure.ac:AC_OUTPUT( SUBSTFOR configure.ac:Makefile SUBSTFOR configure.in:AC_OUTPUT([Makefile @@ -1182,6 +1113,7 @@ gst/gstversion.h gst/types/Makefile gst/elements/Makefile gst/autoplug/Makefile +gst/schedulers/Makefile libs/Makefile libs/riff/Makefile libs/getbits/Makefile @@ -1237,7 +1169,6 @@ plugins/oss/Makefile plugins/rtp/Makefile plugins/mulaw/Makefile plugins/alaw/Makefile -dnl until ffmpeg is handled by configure plugins/ffmpeg/Makefile plugins/filters/Makefile plugins/filters/smooth/Makefile plugins/filters/median/Makefile @@ -1255,6 +1186,7 @@ plugins/filters/cutter/Makefile plugins/filters/deinterlace/Makefile plugins/filters/volume/Makefile plugins/filters/speed/Makefile +plugins/filters/playondemand/Makefile plugins/gnomevfs/Makefile plugins/icecast/Makefile plugins/icecast/icecastsend/Makefile @@ -1294,11 +1226,9 @@ plugins/synthesis/Makefile plugins/synthesis/sinesrc/Makefile plugins/silence/Makefile gstplay/Makefile -dnl components/bonobo-gstmediaplay/Makefile test/Makefile test/xml/Makefile test/bindings/Makefile -dnl someone should fix this test/misc/Makefile test/memchunk/Makefile test/events/Makefile tests/Makefile @@ -1310,6 +1240,7 @@ testsuite/bytestream/Makefile testsuite/capsnego/Makefile testsuite/refcounting/Makefile testsuite/plugin/Makefile +testsuite/threads/Makefile tests/nego/Makefile examples/Makefile examples/autoplug/Makefile diff --git a/docs/gst/.gitignore b/docs/gst/.gitignore index 80491c9cb6..099652a986 100644 --- a/docs/gst/.gitignore +++ b/docs/gst/.gitignore @@ -6,6 +6,7 @@ gstreamer.signals gstreamer.types gstreamer.html gstreamer-unused.txt +gstreamer-undocumented.txt gstreamer-decl-list.txt gstreamer-decl.txt gstreamer-scan.c diff --git a/docs/random/wtay/threads_hilevel b/docs/random/wtay/threads_hilevel index 263ec6d5d8..f8eb9e35ad 100644 --- a/docs/random/wtay/threads_hilevel +++ b/docs/random/wtay/threads_hilevel @@ -100,6 +100,7 @@ flow: unlock (release lock) ! ! status = iterate() (*) lock mutex + signal TH if (!status) // EOS unset SPINNING flag } diff --git a/editor/Makefile.am b/editor/Makefile.am index 0b426547b1..9be4d57d51 100644 --- a/editor/Makefile.am +++ b/editor/Makefile.am @@ -1,5 +1,3 @@ -CFLAGS += -DDATADIR="\"$(gladedir)/\"" $(GNOME_CFLAGS) $(LIBGLADE_GNOME_CFLAGS) -LDFLAGS += $(GNOME_LIBS) $(LIBGLADE_GNOME_LIBS) lib_LTLIBRARIES = libgsteditor.la @@ -19,6 +17,9 @@ libgsteditor_la_SOURCES = \ gstelementselect.c \ gsteditorcreate.c +libgsteditor_la_CFLAGS = -DDATADIR="\"$(gladedir)/\"" $(GNOME_CFLAGS) $(LIBGLADE_GNOME_CFLAGS) +libgsteditor_la_LDFLAGS = $(GNOME_LIBS) $(LIBGLADE_GNOME_LIBS) + libgsteditorincludedir = $(includedir)/gst libgsteditorinclude_HEADERS = \ gsteditor.h diff --git a/examples/autoplug/Makefile.am b/examples/autoplug/Makefile.am index f263f27100..8f8cdd4153 100644 --- a/examples/autoplug/Makefile.am +++ b/examples/autoplug/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = autoplug # just an app here, we're safe -LIBS += $(GNOME_LIBS) $(GST_LIBS) -CFLAGS += $(GNOME_CFLAGS) $(GST_CFLAGS) +autoplug_LDADD = $(GNOME_LIBS) $(GST_LIBS) $(GLIB_LIBS) +autoplug_CFLAGS = $(GNOME_CFLAGS) $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/examples/cutter/Makefile.am b/examples/cutter/Makefile.am index c1fca3f985..29da841f05 100644 --- a/examples/cutter/Makefile.am +++ b/examples/cutter/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = cutter noinst_HEADERS = cutter.h -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +cutter_LDADD = $(GST_LIBS) +cutter_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/examples/helloworld/Makefile.am b/examples/helloworld/Makefile.am index 77e8ef336a..5821f461f2 100644 --- a/examples/helloworld/Makefile.am +++ b/examples/helloworld/Makefile.am @@ -1,4 +1,4 @@ noinst_PROGRAMS = helloworld -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +helloworld_LDADD = $(GST_LIBS) +helloworld_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/examples/helloworld2/Makefile.am b/examples/helloworld2/Makefile.am index 6d686a4092..1daf5c0da1 100644 --- a/examples/helloworld2/Makefile.am +++ b/examples/helloworld2/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = helloworld2 -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +helloworld2_LDADD = $(GST_LIBS) +helloworld2_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/examples/launch/Makefile.am b/examples/launch/Makefile.am index 11c2e57cfc..c1d844569c 100644 --- a/examples/launch/Makefile.am +++ b/examples/launch/Makefile.am @@ -1,8 +1,8 @@ noinst_PROGRAMS = mp3parselaunch # just an app here, we're safe -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +mp3parselaunch_LDADD = $(GST_LIBS) +mp3parselaunch_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) noinst_SCRIPTS = mp3play EXTRA_DIST = mp3play diff --git a/examples/mixer/Makefile.am b/examples/mixer/Makefile.am index d15b425208..8d993da8c7 100644 --- a/examples/mixer/Makefile.am +++ b/examples/mixer/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = mixer noinst_HEADERS = mixer.h -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +mixer_LDADD = $(GST_LIBS) +mixer_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/examples/mixer/mixer.c b/examples/mixer/mixer.c index 7a02eddcb4..ec492cad34 100644 --- a/examples/mixer/mixer.c +++ b/examples/mixer/mixer.c @@ -190,7 +190,7 @@ int main(int argc,char *argv[]) gst_element_set_state(main_bin, GST_STATE_PLAYING); // write out the schedule - gst_schedule_show(GST_ELEMENT_SCHED(main_bin)); + gst_scheduler_show(GST_ELEMENT_SCHED(main_bin)); playing = TRUE; j = 0; diff --git a/examples/plugins/Makefile.am b/examples/plugins/Makefile.am index 5e0b9fca0f..11c631711d 100644 --- a/examples/plugins/Makefile.am +++ b/examples/plugins/Makefile.am @@ -1,4 +1,5 @@ noinst_LTLIBRARIES = libexample.la libexample_la_SOURCES = example.c +libexample_la_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) noinst_HEADERS = example.h diff --git a/examples/queue/Makefile.am b/examples/queue/Makefile.am index e4ef4c7ce8..7b67eeabd6 100644 --- a/examples/queue/Makefile.am +++ b/examples/queue/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = queue -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +queue_LDADD = $(GST_LIBS) +queue_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/examples/queue2/Makefile.am b/examples/queue2/Makefile.am index fd4f914bbd..5bd7542f1c 100644 --- a/examples/queue2/Makefile.am +++ b/examples/queue2/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = queue2 -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +queue2_LDADD = $(GST_LIBS) +queue2_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/examples/queue3/Makefile.am b/examples/queue3/Makefile.am index be6313ce6d..de2d00faab 100644 --- a/examples/queue3/Makefile.am +++ b/examples/queue3/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = queue3 -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +queue3_LDADD = $(GST_LIBS) +queue3_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/examples/queue4/Makefile.am b/examples/queue4/Makefile.am index 0b1a4857b8..8d6e2eec95 100644 --- a/examples/queue4/Makefile.am +++ b/examples/queue4/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = queue4 -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +queue4_LDADD = $(GST_LIBS) +queue4_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/examples/thread/Makefile.am b/examples/thread/Makefile.am index 4e019cb731..ae9f9ac759 100644 --- a/examples/thread/Makefile.am +++ b/examples/thread/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = thread -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +thread_LDADD = $(GST_LIBS) +thread_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/examples/typefind/Makefile.am b/examples/typefind/Makefile.am index 57669bdcc0..e8a9b4f1c8 100644 --- a/examples/typefind/Makefile.am +++ b/examples/typefind/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = typefind -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +typefind_LDADD = $(GST_LIBS) +typefind_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/examples/xml/Makefile.am b/examples/xml/Makefile.am index 24b890fd84..7b8e2f4745 100644 --- a/examples/xml/Makefile.am +++ b/examples/xml/Makefile.am @@ -1,5 +1,7 @@ noinst_PROGRAMS = createxml runxml -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +createxml_LDADD = $(GST_LIBS) +createxml_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) +runxml_LDADD = $(GST_LIBS) +runxml_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/gst/Makefile.am b/gst/Makefile.am index f881cafd30..4d09d49fa3 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -52,8 +52,8 @@ endif EXTRA_libgst_la_SOURCES = gstcpuid_i386.s gstmarshal.list gobject2gtk.c gobject2gtk.h gstxml.c gsttypefind.c gstparse.c gstautoplug.c gsttrace.c -SUBDIRS = . types elements $(GST_AUTOPLUG_DIRS) -DIST_SUBDIRS = types elements autoplug +SUBDIRS = . types elements $(GST_AUTOPLUG_DIRS) schedulers +DIST_SUBDIRS = types elements autoplug schedulers libgst_la_SOURCES = \ cothreads.c \ @@ -202,21 +202,19 @@ noinst_HEADERS = \ gstarch.h \ gstpropsprivate.h -CFLAGS = \ - $(LIBGST_CFLAGS) \ +libgst_la_CFLAGS = -D_GNU_SOURCE -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\" \ + $(LIBGST_CFLAGS) $(XML_CFLAGS) $(GLIB_CFLAGS) \ -D_GNU_SOURCE \ -DG_LOG_DOMAIN=g_log_domain_gstreamer \ -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\" \ - \ -W -Wpointer-arith -Wbad-function-cast \ -Wcast-align -Wsign-compare \ -Wmissing-prototypes -Wmissing-declarations \ -Wnested-externs \ -Winline -Wno-unused -CFLAGS = $(LIBGST_CFLAGS) -D_GNU_SOURCE -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\" -Wall -LIBS = $(LIBGST_LIBS) -LDFLAGS = "" +libgst_la_LIBADD = $(XML_LIBS) $(GLIB_LIBS) + libgst_la_LDFLAGS = -version-info $(GST_LIBVERSION) EXTRA_DIST = ROADMAP diff --git a/gst/autoplug/Makefile.am b/gst/autoplug/Makefile.am index 9c84f3384a..56211a67b3 100644 --- a/gst/autoplug/Makefile.am +++ b/gst/autoplug/Makefile.am @@ -13,7 +13,14 @@ libgststaticautoplugrender_la_LDFLAGS = -version-info $(GST_LIBVERSION) libgstautoplugcache_la_LDFLAGS = -version-info $(GST_LIBVERSION) libgstautoplugger_la_LDFLAGS = -version-info $(GST_LIBVERSION) +libgststaticautoplug_la_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) +libgststaticautoplugrender_la_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) +libgstautoplugcache_la_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) +libgstautoplugger_la_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) + noinst_HEADERS = gststaticautoplug.h gststaticautoplugrender.h noinst_PROGRAMS = autoplugtest -autoplugtest_LDADD = $(GST_LIBS) + +autoplugtest_CFLAGS = $(GST_CFLAGS) $(GLIB_CFLAGS) $(XML_CFLAGS) +autoplugtest_LDADD = $(GST_LIBS) $(GLIB_LIBS) $(XML_LIBS) diff --git a/gst/autoplug/autoplugtest.c b/gst/autoplug/autoplugtest.c index 6385286788..bb8895f5c5 100644 --- a/gst/autoplug/autoplugtest.c +++ b/gst/autoplug/autoplugtest.c @@ -9,16 +9,16 @@ void cache_empty(GstElement *element, gpointer private) { gst_element_set_state (pipeline, GST_STATE_PAUSED); gst_element_disconnect(src,"src",cache,"sink"); - gst_schedule_show (GST_ELEMENT_SCHED(pipeline)); + gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); gst_element_disconnect(cache,"src",decoder,"sink"); - gst_schedule_show (GST_ELEMENT_SCHED(pipeline)); + gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); gst_bin_remove (GST_BIN(autobin), cache); - gst_schedule_show (GST_ELEMENT_SCHED(pipeline)); + gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); gst_element_connect(src,"src",decoder,"sink"); - gst_schedule_show (GST_ELEMENT_SCHED(pipeline)); + gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); gst_element_set_state (pipeline, GST_STATE_PLAYING); - gst_schedule_show (GST_ELEMENT_SCHED(pipeline)); + gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); fprintf(stderr,"done with cache_empty\n"); } @@ -32,7 +32,7 @@ void have_type(GstElement *element, GstCaps *caps, GstCaps **private_caps) { gst_element_disconnect(cache,"src",typefind,"sink"); gst_bin_remove(GST_BIN(autobin),typefind); - gst_schedule_show (GST_ELEMENT_SCHED(pipeline)); + gst_scheduler_show (GST_ELEMENT_SCHED(pipeline)); if (strstr(gst_caps_get_mime(caps),"mp3")) { decoder = gst_elementfactory_make ("mad","decoder"); diff --git a/gst/autoplug/gststaticautoplug.c b/gst/autoplug/gststaticautoplug.c index 2306080b1c..2530ad2049 100644 --- a/gst/autoplug/gststaticautoplug.c +++ b/gst/autoplug/gststaticautoplug.c @@ -475,8 +475,6 @@ differ: GST_DEBUG (0,"delaying the creation of a ghostpad for %s\n", GST_ELEMENT_NAME (thesrcelement)); g_signal_connect (G_OBJECT (thesrcelement), "new_pad", G_CALLBACK (autoplug_dynamic_pad), data); - g_signal_connect (G_OBJECT (thesrcelement), "new_ghost_pad", - G_CALLBACK (autoplug_dynamic_pad), data); } } } diff --git a/gst/autoplug/gststaticautoplugrender.c b/gst/autoplug/gststaticautoplugrender.c index 0c71fffc08..d4c9ad1a54 100644 --- a/gst/autoplug/gststaticautoplugrender.c +++ b/gst/autoplug/gststaticautoplugrender.c @@ -95,6 +95,9 @@ plugin_init (GModule *module, GstPlugin *plugin) if (factory != NULL) { gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); } + else { + g_warning ("could not register autoplugger: staticrender"); + } return TRUE; } @@ -232,8 +235,6 @@ gst_autoplug_pads_autoplug (GstElement *src, GstElement *sink) GST_ELEMENT_NAME(src), GST_ELEMENT_NAME(sink)); g_signal_connect (G_OBJECT(src),"new_pad", G_CALLBACK (gst_autoplug_pads_autoplug_func), sink); - g_signal_connect (G_OBJECT(src),"new_ghost_pad", - G_CALLBACK (gst_autoplug_pads_autoplug_func), sink); } } @@ -398,7 +399,7 @@ next: GST_DEBUG (0,"common factory \"%s\"\n", GST_OBJECT_NAME (factory)); - element = gst_elementfactory_create (factory, GST_OBJECT_NAME (factory)); + element = gst_elementfactory_create (factory, g_strdup (GST_OBJECT_NAME (factory))); gst_bin_add (GST_BIN(result), element); if (srcelement != NULL) { @@ -457,7 +458,7 @@ differ: factory = (GstElementFactory *)(factories[i]->data); GST_DEBUG (0,"factory \"%s\"\n", GST_OBJECT_NAME (factory)); - element = gst_elementfactory_create(factory, GST_OBJECT_NAME (factory)); + element = gst_elementfactory_create(factory, g_strdup (GST_OBJECT_NAME (factory))); } else { element = sinkelement; @@ -468,6 +469,7 @@ differ: if (GST_ELEMENT_IS_THREAD_SUGGESTED(element) || use_thread) { GstElement *queue; GstPad *srcpad; + GstElement *current_bin = thebin; use_thread = FALSE; @@ -491,7 +493,7 @@ differ: gst_bin_add(GST_BIN(thebin), element); gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (element)); GST_DEBUG (0,"adding element %s\n", GST_ELEMENT_NAME (thebin)); - gst_bin_add(GST_BIN(result), thebin); + gst_bin_add(GST_BIN(current_bin), thebin); gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (thebin)); thesrcelement = queue; } diff --git a/gst/elements/Makefile.am b/gst/elements/Makefile.am index 64b75fce5a..d9caf8310d 100644 --- a/gst/elements/Makefile.am +++ b/gst/elements/Makefile.am @@ -8,8 +8,6 @@ else GSTHTTPSRC= endif -#CFLAGS += -O2 -Wall -finstrument-functions -DGST_ENABLE_FUNC_INSTRUMENTATION - libgstelements_la_DEPENDENCIES = ../libgst.la libgstelements_la_SOURCES = \ gstelements.c \ @@ -43,8 +41,6 @@ noinst_HEADERS = \ gstaggregator.h \ gststatistics.h -CFLAGS += -O2 -Wall -LDFLAGS += -lm - -libgstelements_la_LIBADD = $(GHTTP_LIBS) +libgstelements_la_CFLAGS = $(GHTTP_CFLAGS) $(GLIB_CFLAGS) $(XML_CFLAGS) +libgstelements_la_LIBADD = $(GHTTP_LIBS) $(GLIB_LIBS) $(XML_LIBS) libgstelements_la_LDFLAGS = -version-info $(GST_LIBVERSION) diff --git a/gst/elements/gstfakesink.c b/gst/elements/gstfakesink.c index 02eb921fa3..69b8740525 100644 --- a/gst/elements/gstfakesink.c +++ b/gst/elements/gstfakesink.c @@ -213,14 +213,6 @@ gst_fakesink_get_property (GObject *object, guint prop_id, GValue *value, GParam } } -/** - * gst_fakesink_chain: - * @pad: the pad this faksink is connected to - * @buffer: the buffer or event that has to be absorbed - * - * Take the buffer or event from the pad and unref it without doing - * anything with it. - */ static void gst_fakesink_chain (GstPad *pad, GstBuffer *buf) { @@ -232,21 +224,12 @@ gst_fakesink_chain (GstPad *pad, GstBuffer *buf) fakesink = GST_FAKESINK (gst_pad_get_parent (pad)); - if (GST_IS_EVENT(buf)) { - GstEvent *event = GST_EVENT (buf); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - g_print("fakesink: have EOS event!\n"); - gst_element_set_state (GST_ELEMENT (fakesink), GST_STATE_PAUSED); - break; - default: - g_print("fakesink: have unhandled event!\n"); - break; - } - gst_event_free (event); + /* + if (GST_IS_EVENT (buf)) { + gst_pad_event_default (pad, GST_EVENT (buf)); return; } + */ if (!fakesink->silent) g_print("fakesink: chain ******* (%s:%s)< (%d bytes, %lld) %p\n", diff --git a/gst/gobject2gtk.h b/gst/gobject2gtk.h index a14203a263..03bd676077 100644 --- a/gst/gobject2gtk.h +++ b/gst/gobject2gtk.h @@ -220,6 +220,14 @@ gtk_signal_emit((GtkObject *)object,signal, ## args ) g_signal_connect(object,name,func,func_data) \ gtk_signal_connect((GtkObject *)object,name,func,func_data) +#define \ +g_signal_handlers_disconnect_by_func(object,func,func_data) \ +gtk_signal_disconnect_by_func((GtkObject *)object,func,func_data) + +#define \ +g_signal_connect_object(object,name,func,func_data) \ +gtk_signal_connect_object((GtkObject *)object,name,func,(GtkObject*)func_data) + #define \ g_signal_emit_by_name(object,name,data,self) \ gtk_signal_emit_by_name ((GtkObject *)object,name,data,self) @@ -251,8 +259,8 @@ GSList* g_slist_delete_link (GSList *list, GSList *link) __attribute__ ((no_ins typedef struct _GParamSpec GParamSpec; struct _GParamSpec { gchar *name; - gint value_type; - gint flags; + GType value_type; + GParamFlags flags; }; #define g_value_init(value,t) ((value)->type = (t)) diff --git a/gst/gst.c b/gst/gst.c index c6afbb12d5..6b47f66aa8 100644 --- a/gst/gst.c +++ b/gst/gst.c @@ -24,17 +24,8 @@ #include "gst_private.h" -#include "gstversion.h" -#include "gstcpu.h" -#include "gsttype.h" -#include "gstplugin.h" -#include "gstbuffer.h" -#include "gstbin.h" -#include "gstpipeline.h" -#include "gstthread.h" +#include "gst.h" #include "gstqueue.h" -#include "gstautoplug.h" -#include "gstscheduler.h" #ifndef GST_DISABLE_TYPEFIND #include "gsttypefind.h" #endif @@ -118,7 +109,7 @@ gst_init (int *argc, char **argv[]) gst_elementfactory_get_type (); gst_element_get_type (); gst_typefactory_get_type (); - gst_schedule_get_type (); + gst_schedulerfactory_get_type (); gst_bin_get_type (); #ifndef GST_DISABLE_AUTOPLUG gst_autoplugfactory_get_type (); @@ -166,7 +157,6 @@ split_and_iterate (const gchar *stringlist, gchar *separator, GFunc iterator) while (lastlist) { strings = g_strsplit (lastlist, separator, MAX_PATH_SPLIT); - //strings = g_strsplit (lastlist, G_SEARCHPATH_SEPARATOR_S, MAX_PATH_SPLIT); g_free (lastlist); lastlist = NULL; diff --git a/gst/gst.h b/gst/gst.h index 032d5d2c57..5fed0630f8 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -60,7 +60,7 @@ extern "C" { #endif /* __cplusplus */ /* initialize GST */ -void gst_init(int *argc,char **argv[]); +void gst_init (int *argc, char **argv[]); void gst_main (void); void gst_main_quit (void); diff --git a/gst/gstautoplug.c b/gst/gstautoplug.c index c1c813e65e..10e6df1b54 100644 --- a/gst/gstautoplug.c +++ b/gst/gstautoplug.c @@ -365,7 +365,7 @@ gst_autoplugfactory_make (const gchar *name) if (factory == NULL) return NULL; - return gst_autoplugfactory_create (factory);; + return gst_autoplugfactory_create (factory); } #ifndef GST_DISABLE_REGISTRY diff --git a/gst/gstbin.c b/gst/gstbin.c index 9a149d2b5f..579fce9a9a 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -45,6 +45,8 @@ static GstElementStateReturn gst_bin_change_state_norecurse (GstBin *bin); static gboolean gst_bin_change_state_type (GstBin *bin, GstElementState state, GType type); +static void gst_bin_child_state_change (GstBin *bin, GstElementState old, + GstElementState new, GstElement *child); static gboolean gst_bin_iterate_func (GstBin *bin); @@ -135,7 +137,6 @@ gst_bin_init (GstBin *bin) bin->children = NULL; bin->eos_providers = NULL; bin->num_eos_providers = 0; - bin->chains = NULL; bin->eoscond = g_cond_new (); } @@ -154,23 +155,15 @@ gst_bin_new (const gchar *name) } static inline void -gst_bin_reset_element_sched (GstElement *element, GstSchedule *sched) +gst_bin_reset_element_sched (GstElement *element, GstScheduler *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); } static void -gst_bin_set_element_sched (GstElement *element,GstSchedule *sched) +gst_bin_set_element_sched (GstElement *element,GstScheduler *sched) { GList *children; GstElement *child; @@ -178,21 +171,20 @@ gst_bin_set_element_sched (GstElement *element,GstSchedule *sched) 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)); + g_return_if_fail (GST_IS_SCHEDULER(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)) { + 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); + gst_scheduler_add_element (sched, element); // set the children's schedule children = GST_BIN(element)->children; @@ -205,7 +197,7 @@ gst_bin_set_element_sched (GstElement *element,GstSchedule *sched) // otherwise, if it's just a regular old element } else { - GST_SCHEDULE_ADD_ELEMENT (sched, element); + gst_scheduler_add_element (sched, element); } } @@ -232,7 +224,7 @@ gst_bin_unset_element_sched (GstElement *element) // FIXME this check should be irrelevant if (GST_ELEMENT_SCHED (element)) - GST_SCHEDULE_REMOVE_ELEMENT (GST_ELEMENT_SCHED(element), element); + gst_scheduler_remove_element (GST_ELEMENT_SCHED(element), element); // for each child, remove them from their schedule children = GST_BIN(element)->children; @@ -247,7 +239,7 @@ gst_bin_unset_element_sched (GstElement *element) } else { // FIXME this check should be irrelevant if (GST_ELEMENT_SCHED (element)) - GST_SCHEDULE_REMOVE_ELEMENT (GST_ELEMENT_SCHED(element), element); + gst_scheduler_remove_element (GST_ELEMENT_SCHED(element), element); } } @@ -270,27 +262,33 @@ gst_bin_add (GstBin *bin, g_return_if_fail (GST_IS_ELEMENT (element)); GST_DEBUG (GST_CAT_PARENTAGE, "adding element \"%s\" to bin \"%s\"\n", - GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(bin)); + 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); + 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); + 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); + 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)); + g_signal_connect_object (G_OBJECT (element), "state_change", gst_bin_child_state_change, G_OBJECT (bin)); + bin->children = g_list_append (bin->children, element); bin->numchildren++; ///// 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)); + if (GST_IS_BIN(element) && GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) { + GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is a manager"); + } + else if (GST_ELEMENT_SCHED (bin) != NULL) { + gst_bin_set_element_sched (element, GST_ELEMENT_SCHED (bin)); + } GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child \"%s\"", GST_ELEMENT_NAME (element)); @@ -343,6 +341,41 @@ gst_bin_remove (GstBin *bin, gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL); } +static void +gst_bin_child_state_change (GstBin *bin, GstElementState old, GstElementState new, GstElement *child) +{ + gint old_idx = 0, new_idx = 0, i; + + GST_INFO (GST_CAT_STATES, "child %s changed state in bin %s from %s to %s", + GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (bin), + gst_element_statename (old), gst_element_statename (new)); + + while (old>>=1) old_idx++; + while (new>>=1) new_idx++; + + GST_LOCK (bin); + bin->child_states[old_idx]--; + bin->child_states[new_idx]++; + + for (i = GST_NUM_STATES-1; i >= 0; i--) { + if (bin->child_states[i] != 0) { + if (GST_STATE (bin) != (1 << i)) { + GST_INFO (GST_CAT_STATES, "bin %s need state change to %s", + GST_ELEMENT_NAME (bin), gst_element_statename (1<numchildren != 0, GST_STATE_FAILURE); - - -// g_print("-->\n"); children = bin->children; while (children) { child = GST_ELEMENT (children->data); -// GST_DEBUG (GST_CAT_STATES,"setting state on '%s'\n",GST_ELEMENT_NAME (child)); - switch (gst_element_set_state (child, GST_STATE_PENDING (element))) { + children = g_list_next (children); + + switch (gst_element_set_state (child, pending)) { case GST_STATE_FAILURE: GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING; 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; + pending, gst_element_statename (pending)); + + gst_element_set_state (child, old_state); + if (GST_ELEMENT_SCHED (child) == GST_ELEMENT_SCHED (element)) { + return GST_STATE_FAILURE; + } break; case GST_STATE_ASYNC: GST_DEBUG (GST_CAT_STATES,"child '%s' is changing state asynchronously\n", GST_ELEMENT_NAME (child)); + have_async = TRUE; break; } -// g_print("\n"); - children = g_list_next (children); } -// 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); + gst_element_statename (old_state), + gst_element_statename (pending)); + + if (have_async) + ret = GST_STATE_ASYNC; + else + ret = GST_STATE_SUCCESS; return ret; } @@ -410,20 +445,16 @@ gst_bin_change_state_norecurse (GstBin *bin) } static gboolean -gst_bin_change_state_type(GstBin *bin, - GstElementState state, - GType type) +gst_bin_change_state_type (GstBin *bin, + GstElementState state, + GType type) { GList *children; GstElement *child; -// g_print("gst_bin_change_state_type(\"%s\",%d,%d);\n", -// 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); -// g_print("-->\n"); children = bin->children; while (children) { child = GST_ELEMENT (children->data); @@ -434,11 +465,10 @@ gst_bin_change_state_type(GstBin *bin, if (!gst_element_set_state (child,state)) return FALSE; } -// g_print("\n"); children = g_list_next (children); } if (type == GST_TYPE_BIN) - gst_element_set_state (GST_ELEMENT (bin),state); + gst_element_set_state (GST_ELEMENT (bin), state); return TRUE; } @@ -646,6 +676,18 @@ gst_bin_restore_thyself (GstObject *object, } #endif /* GST_DISABLE_LOADSAVE */ +static gboolean +gst_bin_iterate_func (GstBin *bin) +{ + // only iterate if this is the manager bin + if (GST_ELEMENT_SCHED(bin)->parent == GST_ELEMENT (bin)) { + return gst_scheduler_iterate (GST_ELEMENT_SCHED(bin)); + } else { + g_warning ("bin \"%d\" can't be iterated on!\n", GST_ELEMENT_NAME (bin)); + } + + return FALSE; +} /** * gst_bin_iterate: @@ -671,8 +713,14 @@ gst_bin_iterate (GstBin *bin) GST_DEBUG_LEAVE("(\"%s\")",GST_ELEMENT_NAME (bin)); -// if (!running) - // gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED); + if (!running) { + if (GST_STATE (bin) == GST_STATE_PLAYING && GST_STATE_PENDING (bin) == GST_STATE_VOID_PENDING) { + GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, bin, "waiting for child shutdown after useless iteration\n"); + //gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED); + gst_element_wait_state_change (GST_ELEMENT (bin)); + GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, bin, "child shutdown\n"); + } + } return running; } @@ -692,22 +740,3 @@ gst_bin_received_eos (GstElement *element, GstBin *bin) GST_UNLOCK (bin); } -typedef struct { - gulong offset; - gulong size; -} region_struct; - - -static gboolean -gst_bin_iterate_func (GstBin *bin) -{ - // 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"); - } - - return FALSE; -} - diff --git a/gst/gstbin.h b/gst/gstbin.h index f8e2c6d7ca..2a9c22cf9f 100644 --- a/gst/gstbin.h +++ b/gst/gstbin.h @@ -64,7 +64,6 @@ typedef enum { //typedef struct _GstBin GstBin; //typedef struct _GstBinClass GstBinClass; -typedef struct __GstBinChain _GstBinChain; struct _GstBin { GstElement element; @@ -76,16 +75,8 @@ struct _GstBin { GList *eos_providers; GCond *eoscond; - /* iteration state */ - gboolean need_cothreads; - GList *managed_elements; - gint num_managed_elements; - - GList *chains; - gint num_chains; - GList *entries; - gint num_entries; - + GstElementState child_states[GST_NUM_STATES]; + cothread_context *threadcontext; }; @@ -104,37 +95,20 @@ struct _GstBinClass { gboolean (*iterate) (GstBin *bin); }; -struct __GstBinChain { - GList *elements; - gint num_elements; - - GList *entries; - - gboolean need_cothreads; - gboolean need_scheduling; -}; - - GType gst_bin_get_type (void); GstElement* gst_bin_new (const gchar *name); #define gst_bin_destroy(bin) gst_object_destroy(GST_OBJECT(bin)) /* add and remove elements from the bin */ -void gst_bin_add (GstBin *bin, - GstElement *element); -void gst_bin_remove (GstBin *bin, - GstElement *element); +void gst_bin_add (GstBin *bin, GstElement *element); +void gst_bin_remove (GstBin *bin, GstElement *element); /* retrieve a single element or the list of children */ -GstElement* gst_bin_get_by_name (GstBin *bin, - const gchar *name); -GstElement* gst_bin_get_by_name_recurse_up (GstBin *bin, - const gchar *name); +GstElement* gst_bin_get_by_name (GstBin *bin, const gchar *name); +GstElement* gst_bin_get_by_name_recurse_up (GstBin *bin, const gchar *name); GList* gst_bin_get_list (GstBin *bin); -gboolean gst_bin_set_state_type (GstBin *bin, - GstElementState state, - GType type); +gboolean gst_bin_set_state_type (GstBin *bin, GstElementState state, GType type); gboolean gst_bin_iterate (GstBin *bin); diff --git a/gst/gstbuffer.c b/gst/gstbuffer.c index 1a45f4f83b..eedf8fd9f1 100644 --- a/gst/gstbuffer.c +++ b/gst/gstbuffer.c @@ -46,6 +46,7 @@ _gst_buffer_initialize (void) 0, // sizeof(object), 0, NULL, + NULL, }; // round up to the nearest 32 bytes for cache-line and other efficiencies @@ -173,10 +174,10 @@ gst_buffer_create_sub (GstBuffer *parent, buffer->maxsize = parent->size - offset; // deal with bogus/unknown offsets - if (parent->offset != -1) + if (parent->offset != (guint32)-1) buffer->offset = parent->offset + offset; else - buffer->offset = -1; + buffer->offset = (guint32)-1; // again, for lack of better, copy parent's timestamp buffer->timestamp = parent->timestamp; @@ -240,6 +241,7 @@ gst_buffer_append (GstBuffer *buffer, newbuf->data = g_malloc (newbuf->size); memcpy (newbuf->data, buffer->data, buffer->size); memcpy (newbuf->data+buffer->size, append->data, append->size); + GST_BUFFER_TIMESTAMP (newbuf) = GST_BUFFER_TIMESTAMP (buffer); GST_BUFFER_UNLOCK (buffer); gst_buffer_unref (buffer); buffer = newbuf; @@ -489,7 +491,7 @@ gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len) // copy the second buffer's data across memcpy(newbuf->data + (buf1->size - offset), buf2->data, len - (buf1->size - offset)); - if (newbuf->offset != -1) + if (newbuf->offset != (guint32)-1) newbuf->offset = buf1->offset + offset; newbuf->timestamp = buf1->timestamp; if (buf2->maxage > buf1->maxage) newbuf->maxage = buf2->maxage; @@ -518,6 +520,11 @@ gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len) GstBuffer * gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2) { + GstBuffer *result; // we're just a specific case of the more general gst_buffer_span() - return gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size); + result = gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size); + + GST_BUFFER_TIMESTAMP (result) = GST_BUFFER_TIMESTAMP (buf1); + + return result; } diff --git a/gst/gstelement.c b/gst/gstelement.c index e7597af6a6..bcf8d50f3c 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -21,6 +21,7 @@ */ //#define GST_DEBUG_ENABLED +#include #include "gst_private.h" #include "gstelement.h" @@ -34,8 +35,6 @@ enum { STATE_CHANGE, NEW_PAD, PAD_REMOVED, - NEW_GHOST_PAD, - GHOST_PAD_REMOVED, ERROR, EOS, LAST_SIGNAL @@ -103,54 +102,44 @@ gst_element_class_init (GstElementClass *klass) gst_element_signals[STATE_CHANGE] = g_signal_new ("state_change", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstElementClass, state_change), NULL, NULL, - gst_marshal_VOID__INT, G_TYPE_NONE, 1, - G_TYPE_INT); + G_STRUCT_OFFSET (GstElementClass, state_change), NULL, NULL, + gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2, + G_TYPE_INT, G_TYPE_INT); gst_element_signals[NEW_PAD] = g_signal_new ("new_pad", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstElementClass, new_pad), NULL, NULL, - gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, - GST_TYPE_PAD); + G_STRUCT_OFFSET (GstElementClass, new_pad), NULL, NULL, + gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, + GST_TYPE_PAD); gst_element_signals[PAD_REMOVED] = g_signal_new ("pad_removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL, - gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, - GST_TYPE_PAD); - gst_element_signals[NEW_GHOST_PAD] = - g_signal_new ("new_ghost_pad", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstElementClass, new_ghost_pad), NULL, NULL, - gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, - GST_TYPE_PAD); - gst_element_signals[GHOST_PAD_REMOVED] = - g_signal_new ("ghost_pad_removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstElementClass, ghost_pad_removed), NULL, NULL, - gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, - GST_TYPE_PAD); + G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL, + gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, + GST_TYPE_PAD); gst_element_signals[ERROR] = g_signal_new ("error", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL, - gst_marshal_VOID__STRING, G_TYPE_NONE,1, - G_TYPE_STRING); + G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL, + gst_marshal_VOID__STRING, G_TYPE_NONE,1, + G_TYPE_STRING); gst_element_signals[EOS] = g_signal_new ("eos", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL, - gst_marshal_VOID__VOID, G_TYPE_NONE, 0); + G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL, + gst_marshal_VOID__VOID, G_TYPE_NONE, 0); - gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_element_set_property); - gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_element_get_property); - gobject_class->dispose = GST_DEBUG_FUNCPTR(gst_element_dispose); + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_element_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_element_get_property); + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose); #ifndef GST_DISABLE_LOADSAVE - gstobject_class->save_thyself = GST_DEBUG_FUNCPTR(gst_element_save_thyself); - gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR(gst_element_restore_thyself); + gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself); + gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR (gst_element_restore_thyself); #endif - klass->change_state = GST_DEBUG_FUNCPTR(gst_element_change_state); - klass->elementfactory = NULL; - klass->padtemplates = NULL; - klass->numpadtemplates = 0; + klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state); + klass->elementfactory = NULL; + klass->padtemplates = NULL; + klass->numpadtemplates = 0; } static void @@ -184,12 +173,8 @@ gst_element_set_property (GObject *object, guint prop_id, const GValue *value, G { GstElementClass *oclass = (GstElementClass *)G_OBJECT_GET_CLASS(object); - GST_SCHEDULE_LOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) ); - if (oclass->set_property) (oclass->set_property)(object,prop_id,value,pspec); - - GST_SCHEDULE_UNLOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) ); } @@ -198,12 +183,8 @@ gst_element_get_property (GObject *object, guint prop_id, GValue *value, GParamS { GstElementClass *oclass = (GstElementClass *)G_OBJECT_GET_CLASS(object); - GST_SCHEDULE_LOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) ); - if (oclass->get_property) (oclass->get_property)(object,prop_id,value,pspec); - - GST_SCHEDULE_UNLOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) ); } @@ -385,7 +366,7 @@ gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name) GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad)); /* emit the NEW_GHOST_PAD signal */ - g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_GHOST_PAD], 0, ghostpad); + g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, ghostpad); } /** @@ -810,6 +791,27 @@ gst_element_get_state (GstElement *element) return GST_STATE (element); } +static void +gst_element_wait_done (GstElement *element, GstElementState old, GstElementState new, GCond *cond) +{ + g_signal_handlers_disconnect_by_func (G_OBJECT (element), gst_element_wait_done, cond); + g_cond_signal (cond); +} + +void +gst_element_wait_state_change (GstElement *element) +{ + GCond *cond = g_cond_new (); + GMutex *mutex = g_mutex_new (); + + g_mutex_lock (mutex); + g_signal_connect (G_OBJECT (element), "state_change", gst_element_wait_done, cond); + g_cond_wait (cond, mutex); + g_mutex_unlock (mutex); + + g_mutex_free (mutex); + g_cond_free (cond); +} /** * gst_element_set_state: * @element: element to change state of @@ -842,7 +844,7 @@ gst_element_set_state (GstElement *element, GstElementState state) curpending = GST_STATE(element); /* loop until the final requested state is set */ - while (GST_STATE(element) != state) { + while (GST_STATE(element) != state && GST_STATE (element) != GST_STATE_VOID_PENDING) { /* move the curpending state in the correct direction */ if (curpending < state) curpending<<=1; else curpending>>=1; @@ -859,24 +861,80 @@ gst_element_set_state (GstElement *element, GstElementState state) if (oclass->change_state) return_val = (oclass->change_state)(element); - /* 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_ELEMENT (GST_CAT_STATES,element,"have failed change_state return\n"); - return return_val; - } - - /* Last thing we do is verify that a successful state change really - * did change the state... */ - if (GST_STATE(element) != curpending) { - GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "element claimed state-change success, but state didn't change\n"); - return GST_STATE_FAILURE; + switch (return_val) { + case GST_STATE_FAILURE: + GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"have failed change_state return\n"); + return return_val; + case GST_STATE_ASYNC: + GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"element will change state async\n"); + return return_val; + default: + /* Last thing we do is verify that a successful state change really + * did change the state... */ + if (GST_STATE(element) != curpending) { + GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "element claimed state-change success, but state didn't change\n"); + return GST_STATE_FAILURE; + } + break; } } return return_val; } +static GstElementStateReturn +gst_element_change_state (GstElement *element) +{ + GstElementState old_state; + + g_return_val_if_fail (element != NULL, GST_STATE_FAILURE); + g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE); + + old_state = GST_STATE (element); + + if (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING || old_state == GST_STATE_PENDING (element)) { + g_warning ("no state change needed for element %s (VOID_PENDING)\n", GST_ELEMENT_NAME (element)); + return GST_STATE_SUCCESS; + } + + GST_INFO (GST_CAT_STATES, "%s default handler sets state from %s to %s %d", GST_ELEMENT_NAME (element), + gst_element_statename (old_state), + gst_element_statename (GST_STATE_PENDING (element)), + GST_STATE_TRANSITION (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)) { + GST_DEBUG (GST_CAT_STATES, "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_scheduler_enable_element (element->sched, element); + } + else if (GST_STATE_TRANSITION (element) == GST_STATE_PLAYING_TO_PAUSED) { + if (GST_ELEMENT_PARENT (element)) { + GST_DEBUG (GST_CAT_STATES, "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_scheduler_disable_element (element->sched, element); + } + + GST_STATE (element) = GST_STATE_PENDING (element); + GST_STATE_PENDING (element) = GST_STATE_VOID_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. + g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE], 0, + old_state, GST_STATE (element)); + + return GST_STATE_SUCCESS; +} + /** * gst_element_get_factory: * @element: element to request the factory @@ -898,53 +956,6 @@ gst_element_get_factory (GstElement *element) return oclass->elementfactory; } - -/** - * gst_element_change_state: - * @element: element to change state of - * - * Changes the state of the element, but more importantly fires off a signal - * indicating the new state. - * The element will have no pending states anymore. - * - * Returns: whether or not the state change was successfully set. - */ -GstElementStateReturn -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); - -// 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)) - GST_DEBUG(GST_CAT_STATES,"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)) - GST_DEBUG(GST_CAT_STATES,"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_VOID_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. - g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE], 0, - GST_STATE (element)); - return GST_STATE_SUCCESS; -} - static void gst_element_dispose (GObject *object) { @@ -1183,14 +1194,14 @@ gst_element_restore_thyself (xmlNodePtr self, GstObject *parent) /** * gst_element_set_sched: * @element: Element to set manager of. - * @sched: @GstSchedule to set. + * @sched: @GstScheduler to set. * * Sets the scheduler of the element. For internal use only, unless you're * writing a new bin subclass. */ void gst_element_set_sched (GstElement *element, - GstSchedule *sched) + GstScheduler *sched) { GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p",sched); element->sched = sched; @@ -1204,7 +1215,7 @@ gst_element_set_sched (GstElement *element, * * Returns: Element's scheduler */ -GstSchedule* +GstScheduler* gst_element_get_sched (GstElement *element) { return element->sched; @@ -1270,7 +1281,7 @@ gst_element_statename (GstElementState state) 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"; + default: return g_strdup_printf ("\033[01;37;41mUNKNOWN!\033[00m(%d)", state); #else case GST_STATE_VOID_PENDING: return "NONE_PENDING";break; case GST_STATE_NULL: return "NULL";break; diff --git a/gst/gstelement.h b/gst/gstelement.h index 9748e9b6d4..41197eb302 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -35,6 +35,7 @@ extern "C" { #endif /* __cplusplus */ +#define GST_NUM_STATES 4 typedef enum { GST_STATE_VOID_PENDING = 0, @@ -106,9 +107,6 @@ typedef enum { /* the element has to be scheduled as a cothread for any sanity */ GST_ELEMENT_USE_COTHREAD, - /* if this element is in EOS */ - GST_ELEMENT_EOS, - /* if this element can handle events */ GST_ELEMENT_EVENT_AWARE, @@ -141,7 +139,7 @@ struct _GstElement { guint8 current_state; guint8 pending_state; GstElement *manager; - GstSchedule *sched; + GstScheduler *sched; GstElementLoopFunction loopfunc; cothread_state *threadstate; @@ -163,12 +161,10 @@ struct _GstElementClass { gint numpadtemplates; /* signal callbacks */ - 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 (*state_change) (GstElement *element, GstElementState old, GstElementState state); + void (*new_pad) (GstElement *element, GstPad *pad); + void (*pad_removed) (GstElement *element, GstPad *pad); + void (*error) (GstElement *element, gchar *error); void (*eos) (GstElement *element); /* local pointers for get/set */ @@ -195,8 +191,8 @@ 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_sched (GstElement *element, GstSchedule *sched); -GstSchedule* gst_element_get_sched (GstElement *element); +void gst_element_set_sched (GstElement *element, GstScheduler *sched); +GstScheduler* gst_element_get_sched (GstElement *element); void gst_element_add_pad (GstElement *element, GstPad *pad); void gst_element_remove_pad (GstElement *element, GstPad *pad); @@ -219,9 +215,11 @@ void gst_element_signal_eos (GstElement *element); GstElementState gst_element_get_state (GstElement *element); -/* called by the app to set the state of the element */ gint gst_element_set_state (GstElement *element, GstElementState state); -const gchar * gst_element_statename (GstElementState state); + +void gst_element_wait_state_change (GstElement *element); + +const gchar* gst_element_statename (GstElementState state); void gst_element_error (GstElement *element, const gchar *error); diff --git a/gst/gstelementfactory.c b/gst/gstelementfactory.c index b2079f9589..4fcb8864c0 100644 --- a/gst/gstelementfactory.c +++ b/gst/gstelementfactory.c @@ -25,15 +25,15 @@ #include "gstelement.h" -static void gst_elementfactory_class_init (GstElementFactoryClass *klass); -static void gst_elementfactory_init (GstElementFactory *factory); +static void gst_elementfactory_class_init (GstElementFactoryClass *klass); +static void gst_elementfactory_init (GstElementFactory *factory); #ifndef GST_DISABLE_REGISTRY -static void gst_elementfactory_restore_thyself (GstObject *object, xmlNodePtr parent); -static xmlNodePtr gst_elementfactory_save_thyself (GstObject *object, xmlNodePtr parent); +static void gst_elementfactory_restore_thyself (GstObject *object, xmlNodePtr parent); +static xmlNodePtr gst_elementfactory_save_thyself (GstObject *object, xmlNodePtr parent); #endif -static void gst_elementfactory_unload_thyself (GstPluginFeature *feature); +static void gst_elementfactory_unload_thyself (GstPluginFeature *feature); /* global list of registered elementfactories */ static GList* _gst_elementfactories; diff --git a/gst/gstevent.c b/gst/gstevent.c index e06ed50cca..f4f289cfc1 100644 --- a/gst/gstevent.c +++ b/gst/gstevent.c @@ -43,6 +43,7 @@ _gst_event_initialize (void) 0, 0, NULL, + NULL, }; // round up to the nearest 32 bytes for cache-line and other efficiencies diff --git a/gst/gstpad.c b/gst/gstpad.c index c753d01b83..a0d6558aca 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -539,9 +539,7 @@ gst_pad_disconnect (GstPad *srcpad, // 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_scheduler_pad_connect (realsrc->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)); @@ -651,9 +649,9 @@ gst_pad_try_connect (GstPad *srcpad, // now tell the scheduler(s) if (realsrc->sched) - GST_SCHEDULE_PAD_CONNECT (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink); + gst_scheduler_pad_connect (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink); else if (realsink->sched) - GST_SCHEDULE_PAD_CONNECT (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink); + gst_scheduler_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)); @@ -723,7 +721,7 @@ gst_pad_get_padtemplate (GstPad *pad) * Set the sceduler for the pad */ void -gst_pad_set_sched (GstPad *pad, GstSchedule *sched) +gst_pad_set_sched (GstPad *pad, GstScheduler *sched) { g_return_if_fail (pad != NULL); g_return_if_fail (GST_IS_PAD (pad)); @@ -739,7 +737,7 @@ gst_pad_set_sched (GstPad *pad, GstSchedule *sched) * * Returns: the scheduler of the pad. */ -GstSchedule* +GstScheduler* gst_pad_get_sched (GstPad *pad) { g_return_val_if_fail (pad != NULL, NULL); @@ -1580,7 +1578,7 @@ gst_pad_select (GList *padlist) { GstPad *pad; - pad = gst_schedule_pad_select (gst_pad_get_sched (GST_PAD (padlist->data)), padlist); + pad = gst_scheduler_pad_select (gst_pad_get_sched (GST_PAD (padlist->data)), padlist); return pad; } @@ -1971,7 +1969,7 @@ gst_pad_event_default (GstPad *pad, GstEvent *event) GList *pads = element->pads; while (pads) { - if (GST_PAD_DIRECTION (pads->data) == GST_PAD_SRC) { + if (GST_PAD_DIRECTION (pads->data) == GST_PAD_SRC && GST_PAD_CONNECTED (pads->data)) { gst_pad_push (GST_PAD (pads->data), GST_BUFFER (gst_event_new (GST_EVENT_TYPE (event)))); } pads = g_list_next (pads); diff --git a/gst/gstpad.h b/gst/gstpad.h index 7eb962afc4..c73ecf740b 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -178,7 +178,7 @@ struct _GstRealPad { guint64 offset; guint64 len; - GstSchedule *sched; + GstScheduler *sched; GstPadChainFunction chainfunc; GstPadChainFunction chainhandler; @@ -361,8 +361,8 @@ void gst_pad_set_parent (GstPad *pad, GstObject *parent); 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_set_sched (GstPad *pad, GstScheduler *sched); +GstScheduler* 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); diff --git a/gst/gstparse.c b/gst/gstparse.c index 533d0cfc5a..bf8ffd7ea6 100644 --- a/gst/gstparse.c +++ b/gst/gstparse.c @@ -383,8 +383,6 @@ gst_parse_launch_cmdline(int argc,char *argv[],GstBin *parent,gst_parse_priv *pr g_signal_connect (G_OBJECT (previous), "new_pad", G_CALLBACK (dynamic_connect), connect); - g_signal_connect (G_OBJECT (previous), "new_ghost_pad", - G_CALLBACK (dynamic_connect), connect); } else { for (j=0; (jchange_state = gst_pipeline_change_state; } @@ -100,8 +100,8 @@ 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_SCHED (pipeline) = gst_schedulerfactory_make ("basic", GST_ELEMENT (pipeline)); + GST_DEBUG (GST_CAT_PIPELINE, "pipeline's scheduler is %p\n", GST_ELEMENT_SCHED (pipeline)); } diff --git a/gst/gstplugin.c b/gst/gstplugin.c index 753c6666da..38c3b5607f 100644 --- a/gst/gstplugin.c +++ b/gst/gstplugin.c @@ -86,6 +86,8 @@ _gst_plugin_initialize (void) PLUGINS_BUILDDIR "/gst/types"); _gst_plugin_paths = g_list_prepend (_gst_plugin_paths, PLUGINS_BUILDDIR "/gst/autoplug"); + _gst_plugin_paths = g_list_prepend (_gst_plugin_paths, + PLUGINS_BUILDDIR "/gst/schedulers"); #endif /* PLUGINS_USE_BUILDDIR */ #ifndef GST_DISABLE_REGISTRY diff --git a/gst/gstqueue.c b/gst/gstqueue.c index f78792d69a..cdad2e7aaf 100644 --- a/gst/gstqueue.c +++ b/gst/gstqueue.c @@ -265,6 +265,7 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf) reader = FALSE; +restart: /* we have to lock the queue since we span threads */ GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locking t:%ld\n", pthread_self ()); g_mutex_lock (queue->qlock); @@ -277,6 +278,8 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf) gst_queue_locked_flush (queue); break; case GST_EVENT_EOS: + GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "eos in on %s %d\n", + GST_ELEMENT_NAME (queue), queue->level_buffers); break; default: gst_pad_event_default (pad, GST_EVENT (buf)); @@ -327,19 +330,13 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf) 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_VOID_PENDING || -// GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING) -GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->sinkpad))))) != -GST_STATE_VOID_PENDING) - { + while (GST_STATE (queue) != GST_STATE_PLAYING) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n"); - if (GST_STATE_PENDING(queue) != GST_STATE_VOID_PENDING) - GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "GST_STATE_PENDING(queue) != GST_STATE_VOID_PENDING)\n"); - if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING) - GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING\n"); g_mutex_unlock (queue->qlock); cothread_switch(cothread_current_main()); + goto restart; } + g_assert (GST_STATE (queue) == GST_STATE_PLAYING); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for not_full, level:%d/%d\n", queue->level_buffers, queue->size_buffers); if (queue->writer) @@ -390,6 +387,7 @@ gst_queue_get (GstPad *pad) writer = FALSE; +restart: /* have to lock for thread-safety */ GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locking t:%ld\n", pthread_self ()); g_mutex_lock (queue->qlock); @@ -399,19 +397,13 @@ gst_queue_get (GstPad *pad) while (queue->level_buffers == 0) { // 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_VOID_PENDING || -// GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING) -GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->srcpad))))) != -GST_STATE_VOID_PENDING) - { + while (GST_STATE (queue) != GST_STATE_PLAYING) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n"); - if (GST_STATE_PENDING(queue) != GST_STATE_VOID_PENDING) - GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "GST_STATE_PENDING(queue) != GST_STATE_VOID_PENDING)\n"); - if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING) - GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING\n"); g_mutex_unlock (queue->qlock); cothread_switch(cothread_current_main()); + goto restart; } + g_assert (GST_STATE (queue) == GST_STATE_PLAYING); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for not_empty, level:%d/%d\n", queue->level_buffers, queue->size_buffers); if (queue->reader) @@ -451,7 +443,7 @@ GST_STATE_VOID_PENDING) GstEvent *event = GST_EVENT(buf); switch (GST_EVENT_TYPE(event)) { case GST_EVENT_EOS: - GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue eos\n"); + GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue \"%s\" eos\n", GST_ELEMENT_NAME (queue)); gst_element_set_state (GST_ELEMENT (queue), GST_STATE_PAUSED); break; default: @@ -467,56 +459,41 @@ gst_queue_change_state (GstElement *element) { GstQueue *queue; GstElementStateReturn ret; + GstElementState new_state; g_return_val_if_fail (GST_IS_QUEUE (element), GST_STATE_FAILURE); queue = GST_QUEUE (element); + GST_DEBUG_ENTER("('%s')", GST_ELEMENT_NAME (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); + g_mutex_lock (queue->qlock); - /* if going down into NULL state, clear out buffers*/ - if (GST_STATE_PENDING (element) == GST_STATE_READY) { - /* otherwise (READY or higher) we need to open the file */ - gst_queue_flush (queue); + new_state = GST_STATE_PENDING (element); + + if (new_state == GST_STATE_PAUSED) { + g_cond_signal (queue->not_full); + g_cond_signal (queue->not_empty); + } + else if (new_state == GST_STATE_READY) { + gst_queue_locked_flush (queue); + } + else if (new_state == GST_STATE_PLAYING) { + if (!GST_PAD_CONNECTED (queue->sinkpad)) { + // FIXME can this be? + if (queue->reader) + g_cond_signal (queue->not_empty); + g_mutex_unlock (queue->qlock); + + return GST_STATE_FAILURE; + } } - // if we haven't failed already, give the parent class a chance to ;-) - if (GST_ELEMENT_CLASS (parent_class)->change_state) - { - gboolean valid_handler = FALSE; - guint state_change_id = g_signal_lookup("state_change", G_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 && - g_signal_has_handler_pending(G_OBJECT(element), state_change_id, 0, FALSE)) - valid_handler = TRUE; - if (valid_handler) - g_signal_handler_block(G_OBJECT(element), state_change_id); - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); - - if (valid_handler) - g_signal_handler_unblock(G_OBJECT(element), state_change_id); - - // UNLOCK, *then* emit signal (if there's one there) - GST_UNLOCK(queue); - if (valid_handler) - g_signal_emit(G_OBJECT (element), state_change_id, 0, GST_STATE(element)); - } - else - { - ret = GST_STATE_SUCCESS; - GST_UNLOCK(queue); - } + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); + g_mutex_unlock (queue->qlock); + GST_DEBUG_LEAVE("('%s')", GST_ELEMENT_NAME (element)); return ret; } diff --git a/gst/gstscheduler.c b/gst/gstscheduler.c index ccef994f6a..d11c93410c 100644 --- a/gst/gstscheduler.c +++ b/gst/gstscheduler.c @@ -1,6 +1,6 @@ /* GStreamer * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans + * 2000 Wim Taymans * * gstscheduler.c: Default scheduling code for most cases * @@ -20,1606 +20,451 @@ * Boston, MA 02111-1307, USA. */ -//#define GST_DEBUG_ENABLED +#define CLASS(obj) GST_SCHEDULER_CLASS (G_OBJECT_GET_CLASS (obj)) + #include "gst_private.h" #include "gstscheduler.h" -GType _gst_schedule_type = 0; - -static int -gst_schedule_loopfunc_wrapper (int argc,char *argv[]) -{ - GstElement *element = GST_ELEMENT (argv); - G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element); - - GST_DEBUG_ENTER("(%d,'%s')",argc,name); - - do { - GST_DEBUG (GST_CAT_DATAFLOW,"calling loopfunc %s for element %s\n", - GST_DEBUG_FUNCPTR_NAME (element->loopfunc),name); - (element->loopfunc) (element); - 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); - - GST_DEBUG_LEAVE("(%d,'%s')",argc,name); - return 0; -} - -static int -gst_schedule_chain_wrapper (int argc,char *argv[]) -{ - GstElement *element = GST_ELEMENT (argv); - G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element); - - GST_DEBUG_ENTER("(\"%s\")",name); - - GST_DEBUG (GST_CAT_DATAFLOW,"stepping through pads\n"); - - do { - GList *pads = element->pads; - - while (pads) { - GstPad *pad = GST_PAD (pads->data); - GstRealPad *realpad; - - pads = g_list_next (pads); - if (!GST_IS_REAL_PAD(pad)) - continue; - realpad = GST_REAL_PAD(pad); - if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SINK) { - GstBuffer *buf; - - GST_DEBUG (GST_CAT_DATAFLOW,"pulling data from %s:%s\n", name, GST_PAD_NAME (pad)); - buf = gst_pad_pull (pad); - if (buf) { - if (GST_IS_EVENT (buf) && !GST_ELEMENT_IS_EVENT_AWARE (element)) { - //gst_pad_event_default (pad, GST_EVENT (buf)); - gst_pad_send_event (pad, GST_EVENT (buf)); - } - else { - GST_DEBUG (GST_CAT_DATAFLOW,"calling chain function of %s:%s\n", name, GST_PAD_NAME (pad)); - GST_RPAD_CHAINFUNC(realpad) (pad, buf); - } - } - 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)); - GST_FLAG_UNSET(element,GST_ELEMENT_COTHREAD_STOPPING); - - GST_DEBUG_LEAVE("(%d,'%s')",argc,name); - return 0; -} - -static int -gst_schedule_src_wrapper (int argc,char *argv[]) -{ - GstElement *element = GST_ELEMENT (argv); - GList *pads; - GstRealPad *realpad; - GstBuffer *buf = NULL; - G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element); - - GST_DEBUG_ENTER("(%d,\"%s\")",argc,name); - - do { - pads = element->pads; - while (pads) { - if (!GST_IS_REAL_PAD(pads->data)) continue; - realpad = (GstRealPad*)(pads->data); - pads = g_list_next(pads); - if (GST_RPAD_DIRECTION(realpad) == GST_PAD_SRC) { - GST_DEBUG (GST_CAT_DATAFLOW,"calling _getfunc for %s:%s\n",GST_DEBUG_PAD_NAME(realpad)); - if (realpad->regiontype != GST_REGION_VOID) { - g_return_val_if_fail (GST_RPAD_GETREGIONFUNC(realpad) != NULL, 0); -// if (GST_RPAD_GETREGIONFUNC(realpad) == NULL) -// fprintf(stderr,"error, no getregionfunc in \"%s\"\n", name); -// else - buf = (GST_RPAD_GETREGIONFUNC(realpad))((GstPad*)realpad,realpad->regiontype,realpad->offset,realpad->len); - realpad->regiontype = GST_REGION_VOID; - } else { - g_return_val_if_fail (GST_RPAD_GETFUNC(realpad) != NULL, 0); -// if (GST_RPAD_GETFUNC(realpad) == NULL) -// fprintf(stderr,"error, no getfunc in \"%s\"\n", name); -// else - buf = GST_RPAD_GETFUNC(realpad) ((GstPad*)realpad); - } - - GST_DEBUG (GST_CAT_DATAFLOW,"calling gst_pad_push on pad %s:%s\n",GST_DEBUG_PAD_NAME(realpad)); - gst_pad_push ((GstPad*)realpad, buf); - } - } - } while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element)); - GST_FLAG_UNSET(element,GST_ELEMENT_COTHREAD_STOPPING); - - GST_DEBUG_LEAVE(""); - return 0; -} - -static void -gst_schedule_chainhandler_proxy (GstPad *pad, GstBuffer *buf) -{ - 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:%s\"'s pen\n",buf,GST_DEBUG_PAD_NAME(peer)); - - // 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", - 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); - } - } - - g_assert (GST_RPAD_BUFPEN(GST_RPAD_PEER(pad)) == NULL); - // 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\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 void -gst_schedule_select_proxy (GstPad *pad, GstBuffer *buf) -{ - GstRealPad *peer = GST_RPAD_PEER(pad); - - g_print ("select proxy (%s:%s)\n",GST_DEBUG_PAD_NAME(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); - - g_assert (GST_RPAD_BUFPEN(GST_RPAD_PEER(pad)) == NULL); - // 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\n",GST_ELEMENT (GST_PAD_PARENT (pad))->threadstate); - g_print ("%p %s\n", GST_ELEMENT (GST_PAD_PARENT (pad)), gst_element_get_name (GST_ELEMENT (GST_PAD_PARENT (pad)))); - GST_ELEMENT (GST_PAD_PARENT (pad))->select_pad = pad; - GST_FLAG_UNSET(GST_PAD_PARENT (pad), GST_ELEMENT_COTHREAD_STOPPING); - cothread_switch (GST_ELEMENT (GST_PAD_PARENT (pad))->threadstate); - - g_print ("done switching\n"); - GST_DEBUG (GST_CAT_DATAFLOW,"done switching\n"); -} - - -static GstBuffer* -gst_schedule_gethandler_proxy (GstPad *pad) -{ - GstBuffer *buf; - GstRealPad *peer = GST_RPAD_PEER(pad); - - 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 \"%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"); - - // now grab the buffer from the pen, clear the pen, and return the buffer - buf = GST_RPAD_BUFPEN(pad); - GST_RPAD_BUFPEN(pad) = NULL; - - return buf; -} - -static GstBuffer* -gst_schedule_pullregionfunc_proxy (GstPad *pad,GstRegionType type,guint64 offset,guint64 len) -{ - GstBuffer *buf; - GstRealPad *peer = GST_RPAD_PEER(pad); - - GST_DEBUG_ENTER("%s:%s,%d,%lld,%lld",GST_DEBUG_PAD_NAME(pad),type,offset,len); - - // put the region info into the pad - GST_RPAD_REGIONTYPE(pad) = type; - GST_RPAD_OFFSET(pad) = offset; - GST_RPAD_LEN(pad) = len; - - // 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", - 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"); - - // now grab the buffer from the pen, clear the pen, and return the buffer - buf = GST_RPAD_BUFPEN(pad); - GST_RPAD_BUFPEN(pad) = NULL; - return buf; -} - - -static void -gst_schedule_cothreaded_chain (GstBin *bin, GstScheduleChain *chain) { - GList *elements; - GstElement *element; - cothread_func wrapper_function; - GList *pads; - GstPad *pad; - - GST_DEBUG (GST_CAT_SCHEDULING,"chain is using COTHREADS\n"); - - // first create thread context - if (bin->threadcontext == NULL) { - GST_DEBUG (GST_CAT_SCHEDULING,"initializing cothread context\n"); - bin->threadcontext = cothread_init (); - } - - // walk through all the chain's elements - elements = chain->elements; - while (elements) { - element = GST_ELEMENT (elements->data); - elements = g_list_next (elements); - - // start out without a wrapper function, we select it later - wrapper_function = NULL; - - // if the element has a loopfunc... - if (element->loopfunc != NULL) { - 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_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_schedule_chain_wrapper); - GST_DEBUG (GST_CAT_SCHEDULING,"element '%s' is a filter, using _chain_wrapper\n",GST_ELEMENT_NAME(element)); - } - } - } - - // now we have to walk through the pads to set up their state - pads = gst_element_get_pad_list (element); - while (pads) { - pad = GST_PAD (pads->data); - pads = g_list_next (pads); - if (!GST_IS_REAL_PAD(pad)) continue; - - // if the element is DECOUPLED or outside the manager, we have to chain - if ((wrapper_function == NULL) || - (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 (GST_CAT_SCHEDULING,"copying chain function into push proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - GST_RPAD_CHAINHANDLER(pad) = GST_RPAD_CHAINFUNC(pad); - } else { - GST_DEBUG (GST_CAT_SCHEDULING,"copying get function into pull proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - GST_RPAD_GETHANDLER(pad) = GST_RPAD_GETFUNC(pad); - GST_RPAD_PULLREGIONFUNC(pad) = GST_RPAD_GETREGIONFUNC(pad); - } - - // otherwise we really are a cothread - } else { - if (gst_pad_get_direction (pad) == GST_PAD_SINK) { - GST_DEBUG (GST_CAT_SCHEDULING,"setting cothreaded push proxy for sinkpad %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - GST_RPAD_CHAINHANDLER(pad) = GST_DEBUG_FUNCPTR(gst_schedule_chainhandler_proxy); - } else { - GST_DEBUG (GST_CAT_SCHEDULING,"setting cothreaded pull proxy for srcpad %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - GST_RPAD_GETHANDLER(pad) = GST_DEBUG_FUNCPTR(gst_schedule_gethandler_proxy); - GST_RPAD_PULLREGIONFUNC(pad) = GST_DEBUG_FUNCPTR(gst_schedule_pullregionfunc_proxy); - } - } - } - - // need to set up the cothread now - if (wrapper_function != NULL) { - if (element->threadstate == NULL) { - // FIXME handle cothread_create returning NULL - element->threadstate = cothread_create (bin->threadcontext); - 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 (GST_CAT_SCHEDULING,"set wrapper function for '%s' to &%s\n",GST_ELEMENT_NAME(element), - GST_DEBUG_FUNCPTR_NAME(wrapper_function)); - } - } -} - -G_GNUC_UNUSED static void -gst_schedule_chained_chain (GstBin *bin, _GstBinChain *chain) { - GList *elements; - GstElement *element; - GList *pads; - GstPad *pad; - - GST_DEBUG (GST_CAT_SCHEDULING,"chain entered\n"); - // walk through all the elements - elements = chain->elements; - while (elements) { - element = GST_ELEMENT (elements->data); - elements = g_list_next (elements); - - // walk through all the pads - pads = gst_element_get_pad_list (element); - while (pads) { - pad = GST_PAD (pads->data); - pads = g_list_next (pads); - if (!GST_IS_REAL_PAD(pad)) continue; - - if (GST_RPAD_DIRECTION(pad) == GST_PAD_SINK) { - GST_DEBUG (GST_CAT_SCHEDULING,"copying chain function into push proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - GST_RPAD_CHAINHANDLER(pad) = GST_RPAD_CHAINFUNC(pad); - } else { - GST_DEBUG (GST_CAT_SCHEDULING,"copying get function into pull proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - GST_RPAD_GETHANDLER(pad) = GST_RPAD_GETFUNC(pad); - GST_RPAD_PULLREGIONFUNC(pad) = GST_RPAD_GETREGIONFUNC(pad); - } - } - } -} - -/* depracated!! */ -static void -gst_bin_schedule_cleanup (GstBin *bin) -{ - GList *chains; - _GstBinChain *chain; - - chains = bin->chains; - while (chains) { - chain = (_GstBinChain *)(chains->data); - chains = g_list_next(chains); - -// g_list_free(chain->disabled); - g_list_free(chain->elements); - g_list_free(chain->entries); - - g_free(chain); - } - g_list_free(bin->chains); - - bin->chains = NULL; -} - -static void -gst_scheduler_handle_eos (GstElement *element, _GstBinChain *chain) -{ - 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; - GSList *pending = NULL; - GList *pads; - GstPad *pad; - GstElement *peerparent; - GList *chains; - 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 (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 - while (elements) { - element = GST_ELEMENT (elements->data); - - // if this is a DECOUPLED element - if (GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) { - // skip this element entirely - GST_DEBUG (GST_CAT_SCHEDULING,"skipping '%s' because it's decoupled\n",GST_ELEMENT_NAME(element)); - elements = g_list_next (elements); - continue; - } - - 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); - // and remove that one from the main list - elements = g_list_remove (elements, element); - - // create a chain structure - chain = g_new0 (_GstBinChain, 1); - chain->need_scheduling = TRUE; - - // for each pending element, walk the pipeline - do { - // retrieve the top of the stack and pop it - element = GST_ELEMENT (pending->data); - pending = g_slist_remove (pending, element); - - // add ourselves to the chain's list of elements - 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 (G_OBJECT (element), "eos", gst_scheduler_handle_eos, chain); - // set the cothreads flag as appropriate - if (GST_FLAG_IS_SET (element, GST_ELEMENT_USE_COTHREAD)) - chain->need_cothreads = TRUE; - if (bin->use_cothreads == TRUE) - chain->need_cothreads = TRUE; - - // if we're managed by the current bin, and we're not decoupled, - // go find all the peers and add them to the list of elements to check - 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 (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 (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 - pads = gst_element_get_pad_list (element); - while (pads) { - pad = GST_PAD (pads->data); - pads = g_list_next (pads); - if (!GST_IS_REAL_PAD(pad)) continue; - 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 (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 (GST_CAT_SCHEDULING,"adding '%s' to list of pending elements\n", - GST_ELEMENT_NAME(peerparent)); - pending = g_slist_prepend (pending, peerparent); - - // if this is a sink pad, then the element on the other side is an entry - if ((GST_RPAD_DIRECTION(pad) == GST_PAD_SINK) && - (GST_FLAG_IS_SET (peerparent, GST_ELEMENT_DECOUPLED))) { - chain->entries = g_list_prepend (chain->entries, peerparent); - gtk_signal_connect (G_OBJECT (peerparent), "eos", gst_scheduler_handle_eos, chain); - GST_DEBUG (GST_CAT_SCHEDULING,"added '%s' as DECOUPLED entry into the chain\n",GST_ELEMENT_NAME(peerparent)); - } - } else - 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 (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(GST_CAT_SCHEDULING,"%s, ",GST_ELEMENT_NAME(element)); - } - } - 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 (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 = (GstScheduleChain *)(chains->data); - chains = g_list_next (chains); - - // schedule as appropriate - if (chain->need_cothreads) { - gst_schedule_cothreaded_chain (bin,chain); - } else { - gst_schedule_chained_chain (bin,chain); - } - } - - GST_DEBUG_LEAVE("(\"%s\")",GST_ELEMENT_NAME(GST_ELEMENT(bin))); -} -*/ - - -/* - // ***** check for possible connections outside - // get the pad's peer - peer = gst_pad_get_peer (pad); - // FIXME this should be an error condition, if not disabled - if (!peer) break; - // get the parent of the peer of the pad - outside = GST_ELEMENT (gst_pad_get_parent (peer)); - // FIXME this should *really* be an error condition - if (!outside) break; - // if it's a source or connection and it's not ours... - if ((GST_IS_SRC (outside) || GST_IS_CONNECTION (outside)) && - (gst_object_get_parent (GST_OBJECT (outside)) != GST_OBJECT (bin))) { - if (gst_pad_get_direction (pad) == GST_PAD_SINK) { - GST_DEBUG (0,"dealing with outside source element %s\n",GST_ELEMENT_NAME(outside)); -// GST_DEBUG (0,"PUNT: copying gethandler ptr from %s:%s to %s:%s (@ %p)\n", -//GST_DEBUG_PAD_NAME(pad->peer),GST_DEBUG_PAD_NAME(pad),&pad->gethandler); -// pad->gethandler = pad->peer->gethandler; -// GST_DEBUG (0,"PUNT: setting chainhandler proxy to fake proxy on %s:%s\n",GST_DEBUG_PAD_NAME(pad->peer)); -// pad->peer->chainhandler = GST_DEBUG_FUNCPTR(gst_bin_chainhandler_fake_proxy); - GST_RPAD_GETHANDLER(pad) = GST_DEBUG_FUNCPTR(gst_bin_gethandler_proxy); - GST_RPAD_PULLREGIONFUNC(pad) = GST_DEBUG_FUNCPTR(gst_bin_pullregionfunc_proxy); - } - } else { -*/ - - - - - -/* - } else if (GST_IS_SRC (element)) { - GST_DEBUG (0,"adding '%s' as entry point, because it's a source\n",GST_ELEMENT_NAME (element)); - bin->entries = g_list_prepend (bin->entries,element); - bin->num_entries++; - cothread_setfunc(element->threadstate,gst_bin_src_wrapper,0,(char **)element); - } - - pads = gst_element_get_pad_list (element); - while (pads) { - pad = GST_PAD(pads->data); - - if (gst_pad_get_direction (pad) == GST_PAD_SINK) { - GST_DEBUG (0,"setting push proxy for sinkpad %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - // set the proxy functions - pad->chainhandler = GST_DEBUG_FUNCPTR(gst_bin_chainhandler_proxy); - GST_DEBUG (0,"chainhandler %p = gst_bin_chainhandler_proxy %p\n",&pad->chainhandler,gst_bin_chainhandler_proxy); - } else if (gst_pad_get_direction (pad) == GST_PAD_SRC) { - GST_DEBUG (0,"setting pull proxies for srcpad %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - // set the proxy functions - GST_RPAD_GETHANDLER(pad) = GST_DEBUG_FUNCPTR(gst_bin_gethandler_proxy); - GST_RPAD_PULLREGIONFUNC(pad) = GST_DEBUG_FUNCPTR(gst_bin_pullregionfunc_proxy); - GST_DEBUG (0,"pad->gethandler(@%p) = gst_bin_gethandler_proxy(@%p)\n", - &pad->gethandler,gst_bin_gethandler_proxy); - pad->pullregionfunc = GST_DEBUG_FUNCPTR(gst_bin_pullregionfunc_proxy); - } - pads = g_list_next (pads); - } - elements = g_list_next (elements); - - // if there are no entries, we have to pick one at random - if (bin->num_entries == 0) - bin->entries = g_list_prepend (bin->entries, GST_ELEMENT(bin->children->data)); - } - } else { - GST_DEBUG (0,"don't need cothreads, looking for entry points\n"); - // we have to find which elements will drive an iteration - elements = bin->children; - while (elements) { - element = GST_ELEMENT (elements->data); - GST_DEBUG (0,"found element \"%s\"\n", GST_ELEMENT_NAME (element)); - if (GST_IS_BIN (element)) { - gst_bin_create_plan (GST_BIN (element)); - } - if (GST_IS_SRC (element)) { - GST_DEBUG (0,"adding '%s' as entry point, because it's a source\n",GST_ELEMENT_NAME (element)); - bin->entries = g_list_prepend (bin->entries, element); - bin->num_entries++; - } - - // go through all the pads, set pointers, and check for connections - pads = gst_element_get_pad_list (element); - while (pads) { - pad = GST_PAD (pads->data); - - if (gst_pad_get_direction (pad) == GST_PAD_SINK) { - GST_DEBUG (0,"found SINK pad %s:%s\n", GST_DEBUG_PAD_NAME(pad)); - - // copy the peer's chain function, easy enough - GST_DEBUG (0,"copying peer's chainfunc to %s:%s's chainhandler\n",GST_DEBUG_PAD_NAME(pad)); - GST_RPAD_CHAINHANDLER(pad) = GST_DEBUG_FUNCPTR(GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad))); - - // need to walk through and check for outside connections -//FIXME need to do this for all pads - // get the pad's peer - peer = GST_RPAD_PEER(pad); - if (!peer) { - GST_DEBUG (0,"found SINK pad %s has no peer\n", GST_ELEMENT_NAME (pad)); - break; - } - // get the parent of the peer of the pad - outside = GST_ELEMENT (GST_PAD_PARENT(peer)); - if (!outside) break; - // if it's a connection and it's not ours... - if (GST_IS_CONNECTION (outside) && - (gst_object_get_parent (GST_OBJECT (outside)) != GST_OBJECT (bin))) { - gst_info("gstbin: element \"%s\" is the external source Connection " - "for internal element \"%s\"\n", - GST_ELEMENT_NAME (GST_ELEMENT (outside)), - GST_ELEMENT_NAME (GST_ELEMENT (element))); - bin->entries = g_list_prepend (bin->entries, outside); - bin->num_entries++; - } - } - else { - GST_DEBUG (0,"found pad %s\n", GST_ELEMENT_NAME (pad)); - } - pads = g_list_next (pads); - - } - elements = g_list_next (elements); - } -*/ - - - - -/* - // If cothreads are needed, we need to not only find elements but - // set up cothread states and various proxy functions. - if (bin->need_cothreads) { - GST_DEBUG (0,"bin is using cothreads\n"); - - // first create thread context - if (bin->threadcontext == NULL) { - GST_DEBUG (0,"initializing cothread context\n"); - bin->threadcontext = cothread_init (); - } - - // walk through all the children - elements = bin->managed_elements; - while (elements) { - element = GST_ELEMENT (elements->data); - elements = g_list_next (elements); - - // start out with a NULL warpper function, we'll set it if we want a cothread - wrapper_function = NULL; - - // have to decide if we need to or can use a cothreads, and if so which wrapper - // first of all, if there's a loopfunc, the decision's already made - if (element->loopfunc != NULL) { - wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_loopfunc_wrapper); - GST_DEBUG (0,"element %s is a loopfunc, must use a cothread\n",GST_ELEMENT_NAME (element)); - } else { - // otherwise we need to decide if it needs a cothread - // if it's complex, or cothreads are preferred and it's *not* decoupled, cothread it - if (GST_FLAG_IS_SET (element,GST_ELEMENT_COMPLEX) || - (GST_FLAG_IS_SET (bin,GST_BIN_FLAG_PREFER_COTHREADS) && - !GST_FLAG_IS_SET (element,GST_ELEMENT_DECOUPLED))) { - // base it on whether we're going to loop through source or sink pads - if (element->numsinkpads == 0) - wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_src_wrapper); - else - wrapper_function = GST_DEBUG_FUNCPTR(gst_bin_chain_wrapper); - } - } - - // walk through the all the pads for this element, setting proxy functions - // the selection of proxy functions depends on whether we're in a cothread or not - pads = gst_element_get_pad_list (element); - while (pads) { - pad = GST_PAD (pads->data); - pads = g_list_next (pads); - - // check to see if someone else gets to set up the element - peer_manager = GST_ELEMENT((pad)->peer->parent)->manager; - if (peer_manager != GST_ELEMENT(bin)) { - GST_DEBUG (0,"WARNING: pad %s:%s is connected outside of bin\n",GST_DEBUG_PAD_NAME(pad)); - } - - // if the wrapper_function is set, we need to use the proxy functions - if (wrapper_function != NULL) { - // set up proxy functions - if (gst_pad_get_direction (pad) == GST_PAD_SINK) { - GST_DEBUG (0,"setting push proxy for sinkpad %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - pad->chainhandler = GST_DEBUG_FUNCPTR(gst_bin_chainhandler_proxy); - } else if (gst_pad_get_direction (pad) == GST_PAD_SRC) { - GST_DEBUG (0,"setting pull proxy for srcpad %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - GST_RPAD_GETHANDLER(pad) = GST_DEBUG_FUNCPTR(gst_bin_gethandler_proxy); - GST_RPAD_PULLREGIONFUNC(pad) = GST_DEBUG_FUNCPTR(gst_bin_pullregionfunc_proxy); - } - } else { - // otherwise we need to set up for 'traditional' chaining - if (gst_pad_get_direction (pad) == GST_PAD_SINK) { - // we can just copy the chain function, since it shares the prototype - GST_DEBUG (0,"copying chain function into push proxy for %s:%s\n", - GST_DEBUG_PAD_NAME(pad)); - pad->chainhandler = pad->chainfunc; - } else if (gst_pad_get_direction (pad) == GST_PAD_SRC) { - // we can just copy the get function, since it shares the prototype - GST_DEBUG (0,"copying get function into pull proxy for %s:%s\n", - GST_DEBUG_PAD_NAME(pad)); - pad->gethandler = pad->getfunc; - } - } - } - - // if a loopfunc has been specified, create and set up a cothread - if (wrapper_function != NULL) { - if (element->threadstate == NULL) { - element->threadstate = cothread_create (bin->threadcontext); - GST_DEBUG (0,"created cothread %p (@%p) for \"%s\"\n",element->threadstate, - &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_FUNCPTR_NAME(wrapper_function)); - } - -// // HACK: if the element isn't decoupled, it's an entry -// if (!GST_FLAG_IS_SET(element,GST_ELEMENT_DECOUPLED)) -// bin->entries = g_list_append(bin->entries, element); - } - - // otherwise, cothreads are not needed - } else { - GST_DEBUG (0,"bin is chained, no cothreads needed\n"); - - elements = bin->managed_elements; - while (elements) { - element = GST_ELEMENT (elements->data); - elements = g_list_next (elements); - - pads = gst_element_get_pad_list (element); - while (pads) { - pad = GST_PAD (pads->data); - pads = g_list_next (pads); - - if (gst_pad_get_direction (pad) == GST_PAD_SINK) { - GST_DEBUG (0,"copying chain function into push proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - pad->chainhandler = pad->chainfunc; - } else { - GST_DEBUG (0,"copying get function into pull proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad)); - pad->gethandler = pad->getfunc; - } - } - } - } -*/ - -static void -gst_schedule_lock_element (GstSchedule *sched,GstElement *element) -{ - if (element->threadstate) - cothread_lock(element->threadstate); -} - -static void -gst_schedule_unlock_element (GstSchedule *sched,GstElement *element) -{ - if (element->threadstate) - 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 void gst_scheduler_class_init (GstSchedulerClass *klass); +static void gst_scheduler_init (GstScheduler *sched); static GstObjectClass *parent_class = NULL; -GType -gst_schedule_get_type (void) +GType +gst_scheduler_get_type (void) { - if (!_gst_schedule_type) { - static const GTypeInfo schedule_info = { - sizeof(GstScheduleClass), + static GType _gst_scheduler_type = 0; + + if (!_gst_scheduler_type) { + static const GTypeInfo scheduler_info = { + sizeof (GstSchedulerClass), NULL, NULL, - (GClassInitFunc)gst_schedule_class_init, + (GClassInitFunc) gst_scheduler_class_init, NULL, NULL, - sizeof(GstSchedule), + sizeof (GstScheduler), 0, - (GInstanceInitFunc)gst_schedule_init, + (GInstanceInitFunc) gst_scheduler_init, NULL }; - _gst_schedule_type = g_type_register_static(GST_TYPE_OBJECT, "GstSchedule", &schedule_info, 0); + + _gst_scheduler_type = g_type_register_static (GST_TYPE_OBJECT, "GstScheduler", + &scheduler_info, G_TYPE_FLAG_ABSTRACT); } - return _gst_schedule_type; + return _gst_scheduler_type; } static void -gst_schedule_class_init (GstScheduleClass *klass) +gst_scheduler_class_init (GstSchedulerClass *klass) { - parent_class = g_type_class_ref(GST_TYPE_OBJECT); + parent_class = g_type_class_ref (GST_TYPE_OBJECT); } static void -gst_schedule_init (GstSchedule *schedule) +gst_scheduler_init (GstScheduler *sched) { - 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->pad_select = GST_DEBUG_FUNCPTR(gst_schedule_pad_select); - schedule->iterate = GST_DEBUG_FUNCPTR(gst_schedule_iterate); } /** - * gst_schedule_new: - * @parent: the parent of the new scheduler - * - * Create a new scheduler for the given parent. - * - * Returns: the new scheduler. - */ -GstSchedule* -gst_schedule_new(GstElement *parent) -{ - GstSchedule *sched = GST_SCHEDULE (g_object_new(GST_TYPE_SCHEDULE,NULL)); - - 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; -} -*/ - -static 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; -} - -static 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); -} - -static 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++; -} - -static 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); -} - -static 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); -} - -static 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; -} - -static 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); - } -} - -/** - * gst_schedule_pad_connect: - * @sched: the scheduler + * gst_scheduler_pad_connect: + * @sched: the schedulerr * @srcpad: the srcpad to connect * @sinkpad: the sinkpad to connect to * * Connect the srcpad to the given sinkpad. */ void -gst_schedule_pad_connect (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad) +gst_scheduler_pad_connect (GstScheduler *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 -static 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; -} - -static 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); - } - } - } - } + if (CLASS (sched)->pad_connect) + CLASS (sched)->pad_connect (sched, srcpad, sinkpad); } /** - * gst_schedule_pad_disconnect: - * @sched: the scheduler + * gst_scheduler_pad_disconnect: + * @sched: the schedulerr * @srcpad: the srcpad to disconnect * @sinkpad: the sinkpad to disconnect from * * Disconnect the srcpad to the given sinkpad. */ void -gst_schedule_pad_disconnect (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad) +gst_scheduler_pad_disconnect (GstScheduler *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); - } + if (CLASS (sched)->pad_disconnect) + CLASS (sched)->pad_disconnect (sched, srcpad, sinkpad); } /** - * gst_schedule_pad_select: - * @sched: the scheduler + * gst_scheduler_pad_select: + * @sched: the schedulerr * @padlist: the padlist to select on * * register the given padlist for a select operation. * * Returns: the pad which received a buffer. */ -GstPad* -gst_schedule_pad_select (GstSchedule *sched, GList *padlist) +GstPad * +gst_scheduler_pad_select (GstScheduler *sched, GList *padlist) { - GstPad *pad = NULL; - GList *padlist2 = padlist; - GST_INFO (GST_CAT_SCHEDULING, "performing select"); - - while (padlist2) { - pad = GST_PAD (padlist2->data); - - if (gst_pad_peek (pad)) { - g_print ("found something in pad %s:%s\n", GST_DEBUG_PAD_NAME (pad)); - return pad; - } - - padlist2 = g_list_next (padlist2); - } - - /* else there is nothing ready to consume, set up the select functions */ - while (padlist) { - pad = GST_PAD (padlist->data); - - GST_RPAD_CHAINHANDLER(pad) = GST_DEBUG_FUNCPTR(gst_schedule_select_proxy); - - padlist = g_list_next (padlist); - } - if (pad != NULL) { - GstRealPad *peer = GST_RPAD_PEER(pad); - - cothread_switch (GST_ELEMENT (GST_PAD_PARENT (peer))->threadstate); - - g_print ("%p %s\n", GST_ELEMENT (GST_PAD_PARENT (pad)), gst_element_get_name (GST_ELEMENT (GST_PAD_PARENT (pad)))); - pad = GST_ELEMENT (GST_PAD_PARENT (pad))->select_pad; - - g_assert (pad != NULL); - g_print ("back from select (%s:%s)\n", GST_DEBUG_PAD_NAME (pad)); - } - return pad; + if (CLASS (sched)->pad_select) + CLASS (sched)->pad_select (sched, padlist); } /** - * gst_schedule_add_element: - * @sched: the scheduler - * @element: the element to add to the scheduler + * gst_scheduler_add_element: + * @sched: the schedulerr + * @element: the element to add to the schedulerr * - * Add an element to the scheduler. + * Add an element to the schedulerr. */ void -gst_schedule_add_element (GstSchedule *sched, GstElement *element) +gst_scheduler_add_element (GstScheduler *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); - } - } - } + if (CLASS (sched)->add_element) + CLASS (sched)->add_element (sched, element); } /** - * gst_schedule_enable_element: - * @sched: the scheduler + * gst_scheduler_enable_element: + * @sched: the schedulerr * @element: the element to enable * * Enable an element for scheduling. */ void -gst_schedule_enable_element (GstSchedule *sched, GstElement *element) +gst_scheduler_enable_element (GstScheduler *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"); + if (CLASS (sched)->enable_element) + CLASS (sched)->enable_element (sched, element); } /** - * gst_schedule_disable_element: - * @sched: the scheduler + * gst_scheduler_disable_element: + * @sched: the schedulerr * @element: the element to disable * * Disable an element for scheduling. */ void -gst_schedule_disable_element (GstSchedule *sched, GstElement *element) +gst_scheduler_disable_element (GstScheduler *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); - } + if (CLASS (sched)->disable_element) + CLASS (sched)->disable_element (sched, element); } /** - * gst_schedule_remove_element: - * @sched: the scheduler + * gst_scheduler_remove_element: + * @sched: the schedulerr * @element: the element to remove * - * Remove an element from the scheduler. + * Remove an element from the schedulerr. */ void -gst_schedule_remove_element (GstSchedule *sched, GstElement *element) +gst_scheduler_remove_element (GstScheduler *sched, GstElement *element) { - GstScheduleChain *chain; + if (CLASS (sched)->remove_element) + CLASS (sched)->remove_element (sched, element); +} - g_return_if_fail (element != NULL); - g_return_if_fail (GST_IS_ELEMENT(element)); +void +gst_scheduler_lock_element (GstScheduler *sched, GstElement *element) +{ + if (CLASS (sched)->lock_element) + CLASS (sched)->lock_element (sched, 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; - } +void +gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element) +{ + if (CLASS (sched)->unlock_element) + CLASS (sched)->unlock_element (sched, element); } /** - * gst_schedule_iterate: - * @sched: the scheduler + * gst_scheduler_iterate: + * @sched: the schedulerr * - * Perform one iteration on the scheduler. + * Perform one iteration on the schedulerr. * * Returns: a boolean indicating something usefull has happened. */ gboolean -gst_schedule_iterate (GstSchedule *sched) +gst_scheduler_iterate (GstScheduler *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_VOID_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!"); -gst_schedule_show(sched); - //eos = TRUE; - //gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED); - } - } else { - GST_INFO (GST_CAT_DATAFLOW,"NO ENABLED ELEMENTS IN CHAIN!!"); - eos = TRUE; - } - -/* - } 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); - 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; + if (CLASS (sched)->iterate) + CLASS (sched)->iterate (sched); } /** - * gst_schedule_show: - * @sched: the scheduler + * gst_scheduler_show: + * @sched: the schedulerr * - * Dump the state of the scheduler + * Dump the state of the schedulerr */ void -gst_schedule_show (GstSchedule *sched) +gst_scheduler_show (GstScheduler *sched) { - GList *chains, *elements; - GstElement *element; - GstScheduleChain *chain; + if (CLASS (sched)->show) + CLASS (sched)->show (sched); +} - if (sched == NULL) { - g_print("schedule doesn't exist for this element\n"); - return; +/* + * Factory stuff starts here + * + */ + +static GList* _gst_schedulerfactories; + +static void gst_schedulerfactory_class_init (GstSchedulerFactoryClass *klass); +static void gst_schedulerfactory_init (GstSchedulerFactory *factory); + +#ifndef GST_DISABLE_REGISTRY +static xmlNodePtr gst_schedulerfactory_save_thyself (GstObject *object, xmlNodePtr parent); +static void gst_schedulerfactory_restore_thyself (GstObject *object, xmlNodePtr parent); +#endif + +static GstPluginFeatureClass *factory_parent_class = NULL; +//static guint gst_schedulerfactory_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_schedulerfactory_get_type (void) +{ + static GType schedulerfactory_type = 0; + + if (!schedulerfactory_type) { + static const GTypeInfo schedulerfactory_info = { + sizeof (GstSchedulerFactoryClass), + NULL, + NULL, + (GClassInitFunc) gst_schedulerfactory_class_init, + NULL, + NULL, + sizeof(GstSchedulerFactory), + 0, + (GInstanceInitFunc) gst_schedulerfactory_init, + NULL + }; + schedulerfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE, + "GstSchedulerFactory", &schedulerfactory_info, 0); + } + return schedulerfactory_type; +} + +static void +gst_schedulerfactory_class_init (GstSchedulerFactoryClass *klass) +{ + GObjectClass *gobject_class; + GstObjectClass *gstobject_class; + GstPluginFeatureClass *gstpluginfeature_class; + + gobject_class = (GObjectClass*)klass; + gstobject_class = (GstObjectClass*)klass; + gstpluginfeature_class = (GstPluginFeatureClass*) klass; + + factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE); + +#ifndef GST_DISABLE_REGISTRY + gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_schedulerfactory_save_thyself); + gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR (gst_schedulerfactory_restore_thyself); +#endif + + _gst_schedulerfactories = NULL; +} + +static void +gst_schedulerfactory_init (GstSchedulerFactory *factory) +{ + _gst_schedulerfactories = g_list_prepend (_gst_schedulerfactories, factory); +} + + +/** + * gst_schedulerfactory_new: + * @name: name of schedulerfactory to create + * @longdesc: long description of schedulerfactory to create + * @type: the gtk type of the GstScheduler element of this factory + * + * Create a new schedulerfactory with the given parameters + * + * Returns: a new #GstSchedulerFactory. + */ +GstSchedulerFactory* +gst_schedulerfactory_new (const gchar *name, const gchar *longdesc, GType type) +{ + GstSchedulerFactory *factory; + + g_return_val_if_fail(name != NULL, NULL); + factory = gst_schedulerfactory_find (name); + if (!factory) { + factory = GST_SCHEDULERFACTORY (g_object_new (GST_TYPE_SCHEDULERFACTORY, NULL)); } - g_return_if_fail(GST_IS_SCHEDULE(sched)); + gst_object_set_name (GST_OBJECT (factory), name); + if (factory->longdesc) + g_free (factory->longdesc); + factory->longdesc = g_strdup (longdesc); + factory->type = type; - g_print("SCHEDULE DUMP FOR MANAGING BIN \"%s\"\n",GST_ELEMENT_NAME(sched->parent)); + return factory; +} - 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); +/** + * gst_schedulerfactory_destroy: + * @factory: factory to destroy + * + * Removes the scheduler from the global list. + */ +void +gst_schedulerfactory_destroy (GstSchedulerFactory *factory) +{ + g_return_if_fail (factory != NULL); - g_print("%s, ",GST_ELEMENT_NAME(element)); + _gst_schedulerfactories = g_list_remove (_gst_schedulerfactories, factory); + + // we don't free the struct bacause someone might have a handle to it.. +} + +/** + * gst_schedulerfactory_find: + * @name: name of schedulerfactory to find + * + * Search for an schedulerfactory of the given name. + * + * Returns: #GstSchedulerFactory if found, NULL otherwise + */ +GstSchedulerFactory* +gst_schedulerfactory_find (const gchar *name) +{ + GList *walk; + GstSchedulerFactory *factory; + + g_return_val_if_fail(name != NULL, NULL); + + GST_DEBUG (0,"gstscheduler: find \"%s\"\n", name); + + walk = _gst_schedulerfactories; + while (walk) { + factory = (GstSchedulerFactory *)(walk->data); + if (!strcmp (name, GST_OBJECT_NAME (factory))) + return factory; + walk = g_list_next (walk); } - 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); + return NULL; +} - g_print("%p: ",chain); +/** + * gst_schedulerfactory_get_list: + * + * Get the global list of schedulerfactories. + * + * Returns: GList of type #GstSchedulerFactory + */ +GList* +gst_schedulerfactory_get_list (void) +{ + return _gst_schedulerfactories; +} - elements = chain->disabled; - while (elements) { - element = GST_ELEMENT(elements->data); - elements = g_list_next(elements); +/** + * gst_schedulerfactory_create: + * @factory: the factory used to create the instance + * + * Create a new #GstScheduler instance from the + * given schedulerfactory. + * + * Returns: A new #GstScheduler instance. + */ +GstScheduler* +gst_schedulerfactory_create (GstSchedulerFactory *factory, GstElement *parent) +{ + GstScheduler *new = NULL; - g_print("!%s, ",GST_ELEMENT_NAME(element)); + g_return_val_if_fail (factory != NULL, NULL); + + if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) { + g_return_val_if_fail (factory->type != 0, NULL); + + new = GST_SCHEDULER (g_object_new (factory->type, NULL)); + new->parent = parent; + } + + return new; +} + +/** + * gst_schedulerfactory_make: + * @name: the name of the factory used to create the instance + * + * Create a new #GstScheduler instance from the + * schedulerfactory with the given name. + * + * Returns: A new #GstScheduler instance. + */ +GstScheduler* +gst_schedulerfactory_make (const gchar *name, GstElement *parent) +{ + GstSchedulerFactory *factory; + + g_return_val_if_fail (name != NULL, NULL); + + factory = gst_schedulerfactory_find (name); + + if (factory == NULL) + return NULL; + + return gst_schedulerfactory_create (factory, parent); +} + +#ifndef GST_DISABLE_REGISTRY +static xmlNodePtr +gst_schedulerfactory_save_thyself (GstObject *object, xmlNodePtr parent) +{ + GstSchedulerFactory *factory; + + g_return_val_if_fail (GST_IS_SCHEDULERFACTORY (object), parent); + + factory = GST_SCHEDULERFACTORY (object); + + if (GST_OBJECT_CLASS (factory_parent_class)->save_thyself) { + GST_OBJECT_CLASS (factory_parent_class)->save_thyself (object, parent); + } + + xmlNewChild (parent, NULL, "longdesc", factory->longdesc); + + return parent; +} + +/** + * gst_schedulerfactory_load_thyself: + * @parent: the parent XML node pointer + * + * Load an schedulerfactory from the given XML parent node. + * + * Returns: A new factory based on the XML node. + */ +static void +gst_schedulerfactory_restore_thyself (GstObject *object, xmlNodePtr parent) +{ + GstSchedulerFactory *factory = GST_SCHEDULERFACTORY (object); + xmlNodePtr children = parent->xmlChildrenNode; + + if (GST_OBJECT_CLASS (factory_parent_class)->restore_thyself) { + GST_OBJECT_CLASS (factory_parent_class)->restore_thyself (object, parent); + } + + while (children) { + if (!strcmp(children->name, "name")) { + gst_object_set_name (GST_OBJECT (factory), xmlNodeGetContent (children)); } - - elements = chain->elements; - while (elements) { - element = GST_ELEMENT(elements->data); - elements = g_list_next(elements); - - g_print("%s, ",GST_ELEMENT_NAME(element)); + if (!strcmp(children->name, "longdesc")) { + factory->longdesc = xmlNodeGetContent (children); } - g_print("\n"); + children = children->next; } } +#endif /* GST_DISABLE_REGISTRY */ diff --git a/gst/gstscheduler.h b/gst/gstscheduler.h index b65c5ed2d8..042664d7b9 100644 --- a/gst/gstscheduler.h +++ b/gst/gstscheduler.h @@ -2,7 +2,7 @@ * Copyright (C) 1999,2000 Erik Walthinsen * 2000 Wim Taymans * - * gstscheduler.h: Header for default scheduler code + * gstschedulerr.h: Header for default schedulerr code * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,40 +24,33 @@ #ifndef __GST_SCHEDULER_H__ #define __GST_SCHEDULER_H__ +#include #include #include - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -extern GType _gst_schedule_type; - -#define GST_TYPE_SCHEDULE (_gst_schedule_type) -# define GST_IS_SCHEDULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SCHEDULE)) -# define GST_IS_SCHEDULE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SCHEDULE)) - -#define GST_SCHEDULE_FAST(obj) ((GstSchedule*)(obj)) -#define GST_SCHEDULE_CLASS_FAST(klass) ((GstScheduleClass*)(klass)) - -#ifdef GST_TYPE_PARANOID -# define GST_SCHEDULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SCHEDULE, GstSchedule)) -# define GST_SCHEDULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SCHEDULE, GstScheduleClass)) -#else -# define GST_SCHEDULE GST_SCHEDULE_FAST -# define GST_SCHEDULE_CLASS GST_SCHEDULE_CLASS_FAST -#endif +#define GST_TYPE_SCHEDULER \ + (gst_scheduler_get_type()) +#define GST_SCHEDULER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SCHEDULER,GstScheduler)) +#define GST_SCHEDULER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SCHEDULER,GstSchedulerClass)) +#define GST_IS_SCHEDULER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SCHEDULER)) +#define GST_IS_SCHEDULER_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SCHEDULER)) #define GST_SCHED_PARENT(sched) ((sched)->parent) -//typedef struct _GstSchedule GstSchedule; -//typedef struct _GstScheduleClass GstScheduleClass; -typedef struct _GstScheduleChain GstScheduleChain; +//typedef struct _GstScheduler GstScheduler; +//typedef struct _GstSchedulerClass GstSchedulerClass; -struct _GstSchedule { +struct _GstScheduler { GstObject object; GstElement *parent; @@ -67,85 +60,80 @@ struct _GstSchedule { 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); - void (*pad_select) (GstSchedule *sched, GList *padlist); - gboolean (*iterate) (GstSchedule *sched); }; -struct _GstScheduleClass { +struct _GstSchedulerClass { GstObjectClass parent_class; + + void (*add_element) (GstScheduler *sched, GstElement *element); + void (*remove_element) (GstScheduler *sched, GstElement *element); + void (*enable_element) (GstScheduler *sched, GstElement *element); + void (*disable_element) (GstScheduler *sched, GstElement *element); + void (*lock_element) (GstScheduler *sched, GstElement *element); + void (*unlock_element) (GstScheduler *sched, GstElement *element); + void (*pad_connect) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); + void (*pad_disconnect) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); + void (*pad_select) (GstScheduler *sched, GList *padlist); + gboolean (*iterate) (GstScheduler *sched); + + /* for debugging */ + void (*show) (GstScheduler *sched); }; -#define GST_SCHEDULE_SAFETY(sched) if (sched) -//#define GST_SCHEDULE_SAFETY(sched) +GType gst_scheduler_get_type (void); -#define GST_SCHEDULE_ADD_ELEMENT(sched,element) G_STMT_START{ \ - GST_SCHEDULE_SAFETY(sched) { ((sched)->add_element((sched),(element))); } \ -}G_STMT_END -#define GST_SCHEDULE_REMOVE_ELEMENT(sched,element) G_STMT_START{ \ - GST_SCHEDULE_SAFETY(sched) { ((sched)->remove_element((sched),(element))); } \ -}G_STMT_END -#define GST_SCHEDULE_ENABLE_ELEMENT(sched,element) G_STMT_START{ \ - GST_SCHEDULE_SAFETY(sched) { ((sched)->enable_element((sched),(element))); } \ -}G_STMT_END -#define GST_SCHEDULE_DISABLE_ELEMENT(sched,element) G_STMT_START{ \ - GST_SCHEDULE_SAFETY(sched) { ((sched)->disable_element((sched),(element))); } \ -}G_STMT_END -#define GST_SCHEDULE_LOCK_ELEMENT(sched,element) G_STMT_START{ \ - GST_SCHEDULE_SAFETY(sched) { if ((sched)->lock_element != NULL) \ - ((sched)->lock_element((sched),(element))); } \ -}G_STMT_END -#define GST_SCHEDULE_UNLOCK_ELEMENT(sched,element) G_STMT_START{ \ - GST_SCHEDULE_SAFETY(sched) { if ((sched)->unlock_element != NULL) \ - ((sched)->unlock_element((sched),(element))); } \ -}G_STMT_END -#define GST_SCHEDULE_PAD_CONNECT(sched,srcpad,sinkpad) G_STMT_START{ \ - GST_SCHEDULE_SAFETY(sched) { ((sched)->pad_connect((sched),(srcpad),(sinkpad))); } \ -}G_STMT_END -#define GST_SCHEDULE_PAD_DISCONNECT(sched,srcpad,sinkpad) G_STMT_START{ \ - GST_SCHEDULE_SAFETY(sched) { ((sched)->pad_disconnect((sched),(srcpad),(sinkpad))); } \ -}G_STMT_END -#define GST_SCHEDULE_ITERATE(sched) \ - ((sched)->iterate((sched))) +void gst_scheduler_add_element (GstScheduler *sched, GstElement *element); +void gst_scheduler_remove_element (GstScheduler *sched, GstElement *element); +void gst_scheduler_enable_element (GstScheduler *sched, GstElement *element); +void gst_scheduler_disable_element (GstScheduler *sched, GstElement *element); +void gst_scheduler_lock_element (GstScheduler *sched, GstElement *element); +void gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element); +void gst_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); +void gst_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); +GstPad* gst_scheduler_pad_select (GstScheduler *sched, GList *padlist); +gboolean gst_scheduler_iterate (GstScheduler *sched); +void gst_scheduler_show (GstScheduler *sched); +/* + * creating schedulers + * + */ +#define GST_TYPE_SCHEDULERFACTORY \ + (gst_schedulerfactory_get_type ()) +#define GST_SCHEDULERFACTORY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SCHEDULERFACTORY, GstSchedulerFactory)) +#define GST_SCHEDULERFACTORY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SCHEDULERFACTORY, GstSchedulerFactoryClass)) +#define GST_IS_SCHEDULERFACTORY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SCHEDULERFACTORY)) +#define GST_IS_SCHEDULERFACTORY_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SCHEDULERFACTORY)) -struct _GstScheduleChain { - GstSchedule *sched; +typedef struct _GstSchedulerFactory GstSchedulerFactory; +typedef struct _GstSchedulerFactoryClass GstSchedulerFactoryClass; - GList *disabled; +struct _GstSchedulerFactory { + GstPluginFeature feature; - GList *elements; - gint num_elements; - - GstElement *entry; - - gint cothreaded_elements; - gboolean schedule; + gchar *longdesc; /* long description of the scheduler (well, don't overdo it..) */ + GType type; /* unique GType of the scheduler */ }; +struct _GstSchedulerFactoryClass { + GstPluginFeatureClass parent; +}; -GType gst_schedule_get_type (void); -GstSchedule* gst_schedule_new (GstElement *parent); +GType gst_schedulerfactory_get_type (void); -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); -GstPad* gst_schedule_pad_select (GstSchedule *sched, GList *padlist); -gboolean gst_schedule_iterate (GstSchedule *sched); +GstSchedulerFactory* gst_schedulerfactory_new (const gchar *name, const gchar *longdesc, GType type); +void gst_schedulerfactory_destroy (GstSchedulerFactory *factory); -void gst_schedule_show (GstSchedule *sched); +GstSchedulerFactory* gst_schedulerfactory_find (const gchar *name); +GList* gst_schedulerfactory_get_list (void); + +GstScheduler* gst_schedulerfactory_create (GstSchedulerFactory *factory, GstElement *parent); +GstScheduler* gst_schedulerfactory_make (const gchar *name, GstElement *parent); #ifdef __cplusplus diff --git a/gst/gstthread.c b/gst/gstthread.c index 65a3793f2d..269203bed9 100644 --- a/gst/gstthread.c +++ b/gst/gstthread.c @@ -53,7 +53,6 @@ enum { enum { ARG_0, - ARG_CREATE_THREAD, }; @@ -73,8 +72,6 @@ static xmlNodePtr gst_thread_save_thyself (GstObject *object, xmlNodePtr paren static void gst_thread_restore_thyself (GstObject *object, xmlNodePtr self); #endif -static void gst_thread_signal_thread (GstThread *thread, gboolean spinning); - static void* gst_thread_main_loop (void *arg); static GstBinClass *parent_class = NULL; @@ -117,10 +114,6 @@ gst_thread_class_init (GstThreadClass *klass) parent_class = g_type_class_ref (GST_TYPE_BIN); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CREATE_THREAD, - g_param_spec_boolean("create_thread", "Create Thread", "Whether to create a thread.", - TRUE,G_PARAM_READWRITE)); - gobject_class->dispose = gst_thread_dispose; #ifndef GST_DISABLE_LOADSAVE @@ -146,16 +139,14 @@ gst_thread_init (GstThread *thread) // 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); - thread->lock = g_mutex_new(); thread->cond = g_cond_new(); - GST_ELEMENT_SCHED(thread) = gst_schedule_new(GST_ELEMENT(thread)); + GST_ELEMENT_SCHED(thread) = gst_schedulerfactory_make ("basic", GST_ELEMENT(thread)); GST_DEBUG(GST_CAT_THREAD, "thread's scheduler is %p\n",GST_ELEMENT_SCHED(thread)); thread->ppid = getpid(); + thread->thread_id = -1; // gst_element_set_manager(GST_ELEMENT(thread),GST_ELEMENT(thread)); } @@ -184,17 +175,6 @@ gst_thread_set_property (GObject *object, guint prop_id, const GValue *value, GP g_return_if_fail (GST_IS_THREAD (object)); switch (prop_id) { - case ARG_CREATE_THREAD: - if (g_value_get_boolean(value)) { - GST_INFO (GST_CAT_THREAD,"turning ON the creation of the thread"); - GST_FLAG_SET (object, GST_THREAD_CREATE); -// 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 (GST_CAT_THREAD,"gstthread: flags are 0x%08x\n", GST_FLAGS (object)); - } - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -208,9 +188,6 @@ gst_thread_get_property (GObject *object, guint prop_id, GValue *value, GParamSp g_return_if_fail (GST_IS_THREAD (object)); switch (prop_id) { - case ARG_CREATE_THREAD: - g_value_set_boolean(value, GST_FLAG_IS_SET (object, GST_THREAD_CREATE)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -247,256 +224,198 @@ gst_thread_new (const gchar *name) 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 transition; - pthread_t self = pthread_self(); - - g_return_val_if_fail (GST_IS_THREAD(element), FALSE); -// 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()); - - transition = GST_STATE_TRANSITION (element); - - 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); - - switch (transition) { - case GST_STATE_NULL_TO_READY: - // set the state to idle - GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING); - 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)) { - 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' - 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, "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: - 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: - 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)->not_empty)); - g_cond_signal((GST_QUEUE(e)->not_full)); - //GST_UNLOCK(e); - } - else - { - GList *pads = GST_ELEMENT_PADS(e); - while (pads) - { - GstRealPad *peer; - GstElement *peerelement; - GstPad *p = GST_PAD(pads->data); - pads = g_list_next(pads); - - peer = GST_PAD_PEER(p); - if (!peer) continue; - - peerelement = GST_PAD_PARENT(peer); - 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)->not_empty); - g_cond_signal(GST_QUEUE(peerelement)->not_full); - //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: - THR_INFO("stopping thread"); - - GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING); - - // 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); - - break; - case GST_STATE_PAUSED_TO_READY: - THR_INFO("stopping 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 stop spinning\n"); - g_mutex_lock(thread->lock); - gst_thread_signal_thread(thread,FALSE); - } - - break; - default: - GST_DEBUG_ELEMENT(GST_CAT_THREAD, element, "UNHANDLED STATE CHANGE! %x\n",transition); - break; - } - - return stateset; -} - -static void gst_thread_update_state (GstThread *thread) +static GstElementStateReturn +gst_thread_update_state (GstThread *thread) { // check for state change if (GST_STATE_PENDING(thread) != GST_STATE_VOID_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)); + return GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread)); } + + return GST_STATE_SUCCESS; +} + + +static GstElementStateReturn +gst_thread_change_state (GstElement * element) +{ + GstThread *thread; + gboolean stateset = GST_STATE_SUCCESS; + gint transition; + pthread_t self = pthread_self (); + + g_return_val_if_fail (GST_IS_THREAD (element), FALSE); + + thread = GST_THREAD (element); + + transition = GST_STATE_TRANSITION (element); + + THR_INFO ("changing state from %s to %s", + gst_element_statename (GST_STATE (element)), + gst_element_statename (GST_STATE_PENDING (element))); + + if (pthread_equal (self, thread->thread_id)) { + 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)); + return gst_thread_update_state (thread); + } + + switch (transition) { + case GST_STATE_NULL_TO_READY: + // set the state to idle + GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING); + + 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' + 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); + break; + case GST_STATE_READY_TO_PAUSED: + THR_INFO ("readying thread"); + g_mutex_lock (thread->lock); + THR_DEBUG ("signaling\n"); + g_cond_signal (thread->cond); + THR_DEBUG ("waiting for ack\n"); + g_cond_wait (thread->cond, thread->lock); + THR_DEBUG ("got ack\n"); + g_mutex_unlock (thread->lock); + break; + case GST_STATE_PAUSED_TO_PLAYING: + THR_DEBUG ("telling thread to start spinning\n"); + g_mutex_lock (thread->lock); + THR_DEBUG ("signaling\n"); + g_cond_signal (thread->cond); + THR_DEBUG ("waiting for ack\n"); + g_cond_wait (thread->cond, thread->lock); + THR_DEBUG ("got ack\n"); + g_mutex_unlock (thread->lock); + break; + case GST_STATE_PLAYING_TO_PAUSED: + { + GList *elements = (element->sched)->elements; + + THR_INFO ("pausing thread"); + + // 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_element_set_state (e, GST_STATE_PAUSED); + } + else { + GList *pads = GST_ELEMENT_PADS (e); + + while (pads) { + GstRealPad *peer; + GstElement *peerelement; + GstPad *p = GST_PAD (pads->data); + + pads = g_list_next (pads); + + peer = GST_PAD_PEER (p); + if (!peer) + continue; + + peerelement = GST_PAD_PARENT (peer); + 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)) { + GstQueue *queue = GST_QUEUE (peerelement); + + THR_DEBUG (" element \"%s\" has pad cross sched boundary\n", GST_ELEMENT_NAME (e)); + // FIXME!! + g_mutex_lock (queue->qlock); + g_cond_signal (queue->not_full); + g_cond_signal (queue->not_empty); + g_mutex_unlock (queue->qlock); + } + } + } + } + THR_DEBUG ("telling thread to pause, signaling\n"); + g_cond_signal (thread->cond); + THR_DEBUG ("waiting for ack\n"); + g_cond_wait (thread->cond, thread->lock); + THR_DEBUG ("got ack\n"); + g_mutex_unlock (thread->lock); + break; + } + case GST_STATE_READY_TO_NULL: + THR_DEBUG ("telling thread to pause (null) - and joining\n"); + //MattH FIXME revisit + g_mutex_lock (thread->lock); + THR_DEBUG ("signaling\n"); + g_cond_signal (thread->cond); + THR_DEBUG ("waiting for ack\n"); + g_cond_wait (thread->cond, thread->lock); + THR_DEBUG ("got ack\n"); + pthread_join (thread->thread_id, NULL); + thread->thread_id = -1; + g_mutex_unlock (thread->lock); + + GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING); + GST_FLAG_UNSET (thread, GST_THREAD_STATE_STARTED); + GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING); + + break; + case GST_STATE_PAUSED_TO_READY: + THR_DEBUG ("telling thread to stop spinning\n"); + g_mutex_lock (thread->lock); + THR_DEBUG ("signaling\n"); + g_cond_signal (thread->cond); + THR_DEBUG ("waiting for ack\n"); + g_cond_wait (thread->cond, thread->lock); + THR_DEBUG ("got ack\n"); + g_mutex_unlock (thread->lock); + + break; + default: + GST_DEBUG_ELEMENT (GST_CAT_THREAD, element, "UNHANDLED STATE CHANGE! %x\n", transition); + break; + } + + return stateset; } /** @@ -512,151 +431,123 @@ gst_thread_main_loop (void *arg) GstThread *thread = GST_THREAD (arg); gint stateset; + g_mutex_lock (thread->lock); + + GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING); + thread->pid = getpid(); THR_INFO_MAIN("thread is running"); // first we need to change the state of all the children - if (GST_ELEMENT_CLASS (parent_class)->change_state) + 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)); -*/ + if (stateset != GST_STATE_SUCCESS) { + THR_DEBUG_MAIN ("state change of children failed\n"); + } + } -// THR_DEBUG_MAIN("indicating spinup\n"); - g_mutex_lock (thread->lock); + + THR_DEBUG_MAIN ("indicating spinup\n"); 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"); + THR_DEBUG_MAIN ("thread has indicated spinup to parent process\n"); /***** THREAD IS NOW IN READY STATE *****/ while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) { // NOTE we hold the thread lock at this point // what we do depends on what state we're in - switch (GST_STATE(thread)) { + 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); + 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); + + g_assert (GST_STATE_PENDING (thread) == GST_STATE_NULL || + GST_STATE_PENDING (thread) == GST_STATE_PAUSED); + // 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) { + gst_thread_update_state (thread); + THR_DEBUG_MAIN ("done with state transition, signaling back to parent process\n"); + g_cond_signal (thread->cond); + // now we decide what to do next + 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; + GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING); + } + continue; 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); + 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); + + g_assert (GST_STATE_PENDING (thread) == GST_STATE_READY || + GST_STATE_PENDING (thread) == GST_STATE_PLAYING); + // 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); + gst_thread_update_state (thread); // 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 + if (GST_STATE (thread) != GST_STATE_PLAYING) { + // either READY or the state change failed for some reason + g_cond_signal (thread->cond); continue; - } else { - g_mutex_unlock(thread->lock); + } + else { + GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING); // 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"); - // FIXME FIXME FIXME this is ugly! - THR_DEBUG_MAIN("iteration failed, something very wrong, spinning to let parent sync\n"); - while (GST_FLAG_IS_SET(thread, GST_THREAD_STATE_SPINNING)) ; - } + gboolean status; + + g_cond_signal (thread->cond); + g_mutex_unlock (thread->lock); + status = gst_bin_iterate (GST_BIN (thread)); + g_mutex_lock (thread->lock); + //g_cond_signal(thread->cond); + + if (!status || GST_STATE_PENDING (thread) != GST_STATE_VOID_PENDING) + GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING); } - g_mutex_lock(thread->lock); + // looks like we were stopped because of a statechange + if (GST_STATE_PENDING (thread)) { + gst_thread_update_state (thread); + } // 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"); + 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); + 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); + gst_thread_update_state (thread); + g_cond_signal (thread->cond); // now we decide what to do next // there's only PAUSED, we we just wait for it continue; + case GST_STATE_NULL: + THR_DEBUG_MAIN ("thread in %s state, preparing to die\n", + gst_element_statename(GST_STATE_NULL)); + GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING); + break; + default: + g_assert_not_reached (); 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"); - } - } - - 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"); - } -*/ - // since we don't unlock at the end of the while loop, do it here g_mutex_unlock (thread->lock); @@ -665,37 +556,6 @@ gst_thread_main_loop (void *arg) 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, gboolean spinning) -{ - // 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); - THR_DEBUG("waiting for ack\n"); - g_cond_wait (thread->cond,thread->lock); - THR_DEBUG("got ack\n"); - - THR_DEBUG("unlocking\n"); - g_mutex_unlock(thread->lock); - THR_DEBUG("unlocked\n"); -} - - #ifndef GST_DISABLE_LOADSAVE static xmlNodePtr gst_thread_save_thyself (GstObject *object, diff --git a/gst/gstthread.h b/gst/gstthread.h index 961457679c..def68e3257 100644 --- a/gst/gstthread.h +++ b/gst/gstthread.h @@ -38,12 +38,9 @@ extern GstElementDetails gst_thread_details; typedef enum { - GST_THREAD_CREATE = GST_BIN_FLAG_LAST, - - GST_THREAD_STATE_STARTED, + GST_THREAD_STATE_STARTED = GST_BIN_FLAG_LAST, GST_THREAD_STATE_SPINNING, GST_THREAD_STATE_REAPING, - GST_THREAD_STATE_ELEMENT_CHANGED, /* padding */ GST_THREAD_FLAG_LAST = GST_BIN_FLAG_LAST + 4, diff --git a/gst/gsttrace.c b/gst/gsttrace.c index 6aad091253..b792169cc4 100644 --- a/gst/gsttrace.c +++ b/gst/gsttrace.c @@ -33,101 +33,119 @@ #include "gstlog.h" #include "gsttrace.h" - -__inline__ void read_tsc(guint64 *dst) { +static __inline__ void +read_tsc (guint64 * dst) +{ #ifdef HAVE_RDTSC guint64 tsc; - __asm__ __volatile__ ("rdtsc" : "=A" (tsc)); + __asm__ __volatile__ ("rdtsc":"=A" (tsc)); + *dst = tsc; #else *dst = 0; #endif } -void gst_trace_read_tsc(guint64 *dst) { - read_tsc(dst); +void +gst_trace_read_tsc (guint64 * dst) +{ + read_tsc (dst); } GstTrace *_gst_trace_default = NULL; gint _gst_trace_on = 1; -GstTrace *gst_trace_new(guchar *filename,gint size) { - GstTrace *trace = g_malloc(sizeof(GstTrace)); +GstTrace * +gst_trace_new (guchar * filename, gint size) +{ + GstTrace *trace = g_malloc (sizeof (GstTrace)); - g_return_val_if_fail(trace != NULL,NULL); - trace->filename = g_strdup(filename); - g_print("opening '%s'\n",trace->filename); - trace->fd = open(trace->filename,O_RDWR|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR); - perror("opening trace file"); - g_return_val_if_fail(trace->fd > 0,NULL); - trace->buf = g_malloc(size * sizeof(GstTraceEntry)); - g_return_val_if_fail(trace->buf != NULL,NULL); + g_return_val_if_fail (trace != NULL, NULL); + trace->filename = g_strdup (filename); + g_print ("opening '%s'\n", trace->filename); + trace->fd = open (trace->filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + perror ("opening trace file"); + g_return_val_if_fail (trace->fd > 0, NULL); + trace->buf = g_malloc (size * sizeof (GstTraceEntry)); + g_return_val_if_fail (trace->buf != NULL, NULL); trace->bufsize = size; trace->bufoffset = 0; return trace; } -void gst_trace_destroy(GstTrace *trace) { - g_return_if_fail(trace != NULL); - g_return_if_fail(trace->buf != NULL); +void +gst_trace_destroy (GstTrace * trace) +{ + g_return_if_fail (trace != NULL); + g_return_if_fail (trace->buf != NULL); - if (gst_trace_get_remaining(trace) > 0) - gst_trace_flush(trace); - close(trace->fd); - g_free(trace->buf); - g_free(trace); + if (gst_trace_get_remaining (trace) > 0) + gst_trace_flush (trace); + close (trace->fd); + g_free (trace->buf); + g_free (trace); } -void gst_trace_flush(GstTrace *trace) { +void +gst_trace_flush (GstTrace * trace) +{ if (!trace) { trace = _gst_trace_default; - if (!trace ) return; + if (!trace) + return; } - write(trace->fd,trace->buf,trace->bufoffset * sizeof(GstTraceEntry)); + write (trace->fd, trace->buf, trace->bufoffset * sizeof (GstTraceEntry)); trace->bufoffset = 0; } -void gst_trace_text_flush(GstTrace *trace) { +void +gst_trace_text_flush (GstTrace * trace) +{ int i; - const int strsize = 20+1 + 10+1 + 10+1 + 112+1 + 1; + const int strsize = 20 + 1 + 10 + 1 + 10 + 1 + 112 + 1 + 1; char str[strsize]; if (!trace) { trace = _gst_trace_default; - if (!trace ) return; + if (!trace) + return; } - for (i=0; ibufoffset; i++) { - snprintf(str, strsize, "%20lld %10d %10d %s\n", - trace->buf[i].timestamp, - trace->buf[i].sequence, - trace->buf[i].data, - trace->buf[i].message); - write(trace->fd,str,strlen(str)); + for (i = 0; i < trace->bufoffset; i++) { + snprintf (str, strsize, "%20lld %10d %10d %s\n", + trace->buf[i].timestamp, + trace->buf[i].sequence, trace->buf[i].data, trace->buf[i].message); + write (trace->fd, str, strlen (str)); } trace->bufoffset = 0; } -void gst_trace_set_default(GstTrace *trace) { - g_return_if_fail(trace != NULL); +void +gst_trace_set_default (GstTrace * trace) +{ + g_return_if_fail (trace != NULL); _gst_trace_default = trace; } -void _gst_trace_add_entry(GstTrace *trace,guint32 seq,guint32 data,gchar *msg) { +void +_gst_trace_add_entry (GstTrace * trace, guint32 seq, guint32 data, gchar * msg) +{ GstTraceEntry *entry; + if (!trace) { trace = _gst_trace_default; - if (!trace ) return; + if (!trace) + return; } entry = trace->buf + trace->bufoffset; - read_tsc(&(entry->timestamp)); + read_tsc (&(entry->timestamp)); entry->sequence = seq; entry->data = data; - strncpy(entry->message,msg,112); + strncpy (entry->message, msg, 112); trace->bufoffset++; - gst_trace_flush(trace); + gst_trace_flush (trace); } diff --git a/gst/gsttypes.h b/gst/gsttypes.h index a7c07ed8fb..e6f0335b41 100644 --- a/gst/gsttypes.h +++ b/gst/gsttypes.h @@ -11,7 +11,7 @@ typedef struct _GstElement GstElement; typedef struct _GstElementClass GstElementClass; typedef struct _GstBin GstBin; typedef struct _GstBinClass GstBinClass; -typedef struct _GstSchedule GstSchedule; -typedef struct _GstScheduleClass GstScheduleClass; +typedef struct _GstScheduler GstScheduler; +typedef struct _GstSchedulerClass GstSchedulerClass; #endif diff --git a/gst/gstutils.c b/gst/gstutils.c index b119a868a4..5e9c55f295 100644 --- a/gst/gstutils.c +++ b/gst/gstutils.c @@ -562,8 +562,9 @@ gst_print_element_args (GString * buf, gint indent, GstElement * element) g_string_append_c (buf, '\n'); - if (G_VALUE_TYPE (&value)) + if (G_VALUE_TYPE (&value)) { g_value_unset (&value); + } } g_free (property_specs); } diff --git a/gst/schedulers/Makefile.am b/gst/schedulers/Makefile.am new file mode 100644 index 0000000000..824b5ed862 --- /dev/null +++ b/gst/schedulers/Makefile.am @@ -0,0 +1,9 @@ +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgstbasicscheduler.la + +libgstbasicscheduler_la_SOURCES = gstbasicscheduler.c + +libgstbasicscheduler_la_LDFLAGS = -version-info $(GST_LIBVERSION) + +libgstbasicscheduler_la_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) diff --git a/gst/schedulers/gstbasicscheduler.c b/gst/schedulers/gstbasicscheduler.c new file mode 100644 index 0000000000..8183193625 --- /dev/null +++ b/gst/schedulers/gstbasicscheduler.c @@ -0,0 +1,1142 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstscheduler.c: Default scheduling code for most cases + * + * 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. + */ + +//#define GST_DEBUG_ENABLED +#include + +typedef struct _GstSchedulerChain GstSchedulerChain; + +struct _GstSchedulerChain { + GstScheduler *sched; + + GList *disabled; + + GList *elements; + gint num_elements; + + GstElement *entry; + + gint cothreaded_elements; + gboolean schedule; +}; + +static GType _gst_basic_scheduler_type = 0; + +static void gst_basic_scheduler_class_init (GstSchedulerClass * klass); +static void gst_basic_scheduler_init (GstScheduler * scheduler); + +static void gst_basic_scheduler_add_element (GstScheduler *sched, GstElement *element); +static void gst_basic_scheduler_remove_element (GstScheduler *sched, GstElement *element); +static void gst_basic_scheduler_enable_element (GstScheduler *sched, GstElement *element); +static void gst_basic_scheduler_disable_element (GstScheduler *sched, GstElement *element); +static void gst_basic_scheduler_lock_element (GstScheduler *sched, GstElement *element); +static void gst_basic_scheduler_unlock_element (GstScheduler *sched, GstElement *element); +static void gst_basic_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); +static void gst_basic_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); +static GstPad* gst_basic_scheduler_pad_select (GstScheduler *sched, GList *padlist); +static gboolean gst_basic_scheduler_iterate (GstScheduler *sched); + +static void gst_basic_scheduler_show (GstScheduler *sched); + +static GstSchedulerClass *parent_class = NULL; + +static GType +gst_basic_scheduler_get_type (void) +{ + if (!_gst_basic_scheduler_type) { + static const GTypeInfo scheduler_info = { + sizeof (GstSchedulerClass), + NULL, + NULL, + (GClassInitFunc) gst_basic_scheduler_class_init, + NULL, + NULL, + sizeof (GstScheduler), + 0, + (GInstanceInitFunc) gst_basic_scheduler_init, + NULL + }; + + _gst_basic_scheduler_type = g_type_register_static (GST_TYPE_SCHEDULER, "GstBasicScheduler", &scheduler_info, 0); + } + return _gst_basic_scheduler_type; +} + +static void +gst_basic_scheduler_class_init (GstSchedulerClass * klass) +{ + GObjectClass *gobject_class; + GstObjectClass *gstobject_class; + + gobject_class = (GObjectClass*)klass; + gstobject_class = (GstObjectClass*)klass; + + parent_class = g_type_class_ref (GST_TYPE_SCHEDULER); + + klass->add_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_add_element); + klass->remove_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_remove_element); + klass->enable_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_enable_element); + klass->disable_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_disable_element); + klass->lock_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_lock_element); + klass->unlock_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_unlock_element); + klass->pad_connect = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_connect); + klass->pad_disconnect = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_disconnect); + klass->pad_select = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_select); + klass->iterate = GST_DEBUG_FUNCPTR (gst_basic_scheduler_iterate); +} + +static void +gst_basic_scheduler_init (GstScheduler *scheduler) +{ +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstSchedulerFactory *factory; + + gst_plugin_set_longname (plugin, "A basic scheduler"); + + factory = gst_schedulerfactory_new ("basic", + "A basic scheduler, it uses cothreads", + gst_basic_scheduler_get_type()); + + if (factory != NULL) { + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + } + else { + g_warning ("could not register scheduler: basic"); + } + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "gstbasicscheduler", + plugin_init +}; + +static int +gst_basic_scheduler_loopfunc_wrapper (int argc, char *argv[]) +{ + GstElement *element = GST_ELEMENT (argv); + G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element); + + GST_DEBUG_ENTER ("(%d,'%s')", argc, name); + + do { + GST_DEBUG (GST_CAT_DATAFLOW, "calling loopfunc %s for element %s\n", + GST_DEBUG_FUNCPTR_NAME (element->loopfunc), name); + (element->loopfunc) (element); + 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); + + GST_DEBUG_LEAVE ("(%d,'%s')", argc, name); + return 0; +} + +static int +gst_basic_scheduler_chain_wrapper (int argc, char *argv[]) +{ + GstElement *element = GST_ELEMENT (argv); + G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element); + + GST_DEBUG_ENTER ("(\"%s\")", name); + + GST_DEBUG (GST_CAT_DATAFLOW, "stepping through pads\n"); + + do { + GList *pads = element->pads; + + while (pads) { + GstPad *pad = GST_PAD (pads->data); + GstRealPad *realpad; + + pads = g_list_next (pads); + if (!GST_IS_REAL_PAD (pad)) + continue; + realpad = GST_REAL_PAD (pad); + if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SINK) { + GstBuffer *buf; + + GST_DEBUG (GST_CAT_DATAFLOW, "pulling data from %s:%s\n", name, GST_PAD_NAME (pad)); + buf = gst_pad_pull (pad); + if (buf) { + if (GST_IS_EVENT (buf) && !GST_ELEMENT_IS_EVENT_AWARE (element)) { + //gst_pad_event_default (pad, GST_EVENT (buf)); + gst_pad_send_event (pad, GST_EVENT (buf)); + } + else { + GST_DEBUG (GST_CAT_DATAFLOW, "calling chain function of %s:%s\n", name, + GST_PAD_NAME (pad)); + GST_RPAD_CHAINFUNC (realpad) (pad, buf); + } + } + 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)); + GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING); + + GST_DEBUG_LEAVE ("(%d,'%s')", argc, name); + return 0; +} + +static int +gst_basic_scheduler_src_wrapper (int argc, char *argv[]) +{ + GstElement *element = GST_ELEMENT (argv); + GList *pads; + GstRealPad *realpad; + GstBuffer *buf = NULL; + G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element); + + GST_DEBUG_ENTER ("(%d,\"%s\")", argc, name); + + do { + pads = element->pads; + while (pads) { + if (!GST_IS_REAL_PAD (pads->data)) + continue; + realpad = (GstRealPad *) (pads->data); + pads = g_list_next (pads); + if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SRC) { + GST_DEBUG (GST_CAT_DATAFLOW, "calling _getfunc for %s:%s\n", GST_DEBUG_PAD_NAME (realpad)); + if (realpad->regiontype != GST_REGION_VOID) { + g_return_val_if_fail (GST_RPAD_GETREGIONFUNC (realpad) != NULL, 0); +// if (GST_RPAD_GETREGIONFUNC(realpad) == NULL) +// fprintf(stderr,"error, no getregionfunc in \"%s\"\n", name); +// else + buf = + (GST_RPAD_GETREGIONFUNC (realpad)) ((GstPad *) realpad, realpad->regiontype, + realpad->offset, realpad->len); + realpad->regiontype = GST_REGION_VOID; + } + else { + g_return_val_if_fail (GST_RPAD_GETFUNC (realpad) != NULL, 0); +// if (GST_RPAD_GETFUNC(realpad) == NULL) +// fprintf(stderr,"error, no getfunc in \"%s\"\n", name); +// else + buf = GST_RPAD_GETFUNC (realpad) ((GstPad *) realpad); + } + + GST_DEBUG (GST_CAT_DATAFLOW, "calling gst_pad_push on pad %s:%s\n", + GST_DEBUG_PAD_NAME (realpad)); + gst_pad_push ((GstPad *) realpad, buf); + } + } + } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); + GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING); + + GST_DEBUG_LEAVE (""); + return 0; +} + +static void +gst_basic_scheduler_chainhandler_proxy (GstPad * pad, GstBuffer * buf) +{ + 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:%s\"'s pen\n", buf, + GST_DEBUG_PAD_NAME (peer)); + + // 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", + 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); + } + } + + g_assert (GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) == NULL); + // 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\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 void +gst_basic_scheduler_select_proxy (GstPad * pad, GstBuffer * buf) +{ + GstRealPad *peer = GST_RPAD_PEER (pad); + + g_print ("select proxy (%s:%s)\n", GST_DEBUG_PAD_NAME (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); + + g_assert (GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) == NULL); + // 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\n", + GST_ELEMENT (GST_PAD_PARENT (pad))->threadstate); + g_print ("%p %s\n", GST_ELEMENT (GST_PAD_PARENT (pad)), + gst_element_get_name (GST_ELEMENT (GST_PAD_PARENT (pad)))); + GST_ELEMENT (GST_PAD_PARENT (pad))->select_pad = pad; + GST_FLAG_UNSET (GST_PAD_PARENT (pad), GST_ELEMENT_COTHREAD_STOPPING); + cothread_switch (GST_ELEMENT (GST_PAD_PARENT (pad))->threadstate); + + g_print ("done switching\n"); + GST_DEBUG (GST_CAT_DATAFLOW, "done switching\n"); +} + + +static GstBuffer * +gst_basic_scheduler_gethandler_proxy (GstPad * pad) +{ + GstBuffer *buf; + GstRealPad *peer = GST_RPAD_PEER (pad); + + 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 \"%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"); + + // now grab the buffer from the pen, clear the pen, and return the buffer + buf = GST_RPAD_BUFPEN (pad); + GST_RPAD_BUFPEN (pad) = NULL; + + return buf; +} + +static GstBuffer * +gst_basic_scheduler_pullregionfunc_proxy (GstPad * pad, GstRegionType type, guint64 offset, guint64 len) +{ + GstBuffer *buf; + GstRealPad *peer = GST_RPAD_PEER (pad); + + GST_DEBUG_ENTER ("%s:%s,%d,%lld,%lld", GST_DEBUG_PAD_NAME (pad), type, offset, len); + + // put the region info into the pad + GST_RPAD_REGIONTYPE (pad) = type; + GST_RPAD_OFFSET (pad) = offset; + GST_RPAD_LEN (pad) = len; + + // 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", + 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"); + + // now grab the buffer from the pen, clear the pen, and return the buffer + buf = GST_RPAD_BUFPEN (pad); + GST_RPAD_BUFPEN (pad) = NULL; + return buf; +} + + +static void +gst_basic_scheduler_cothreaded_chain (GstBin * bin, GstSchedulerChain * chain) +{ + GList *elements; + GstElement *element; + cothread_func wrapper_function; + GList *pads; + GstPad *pad; + + GST_DEBUG (GST_CAT_SCHEDULING, "chain is using COTHREADS\n"); + + // first create thread context + if (bin->threadcontext == NULL) { + GST_DEBUG (GST_CAT_SCHEDULING, "initializing cothread context\n"); + bin->threadcontext = cothread_init (); + } + + // walk through all the chain's elements + elements = chain->elements; + while (elements) { + element = GST_ELEMENT (elements->data); + elements = g_list_next (elements); + + // start out without a wrapper function, we select it later + wrapper_function = NULL; + + // if the element has a loopfunc... + if (element->loopfunc != NULL) { + wrapper_function = GST_DEBUG_FUNCPTR (gst_basic_scheduler_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_basic_scheduler_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_basic_scheduler_chain_wrapper); + GST_DEBUG (GST_CAT_SCHEDULING, "element '%s' is a filter, using _chain_wrapper\n", + GST_ELEMENT_NAME (element)); + } + } + } + + // now we have to walk through the pads to set up their state + pads = gst_element_get_pad_list (element); + while (pads) { + pad = GST_PAD (pads->data); + pads = g_list_next (pads); + if (!GST_IS_REAL_PAD (pad)) + continue; + + // if the element is DECOUPLED or outside the manager, we have to chain + if ((wrapper_function == NULL) || + (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 (GST_CAT_SCHEDULING, "copying chain function into push proxy for %s:%s\n", + GST_DEBUG_PAD_NAME (pad)); + GST_RPAD_CHAINHANDLER (pad) = GST_RPAD_CHAINFUNC (pad); + } + else { + GST_DEBUG (GST_CAT_SCHEDULING, "copying get function into pull proxy for %s:%s\n", + GST_DEBUG_PAD_NAME (pad)); + GST_RPAD_GETHANDLER (pad) = GST_RPAD_GETFUNC (pad); + GST_RPAD_PULLREGIONFUNC (pad) = GST_RPAD_GETREGIONFUNC (pad); + } + + // otherwise we really are a cothread + } + else { + if (gst_pad_get_direction (pad) == GST_PAD_SINK) { + GST_DEBUG (GST_CAT_SCHEDULING, "setting cothreaded push proxy for sinkpad %s:%s\n", + GST_DEBUG_PAD_NAME (pad)); + GST_RPAD_CHAINHANDLER (pad) = GST_DEBUG_FUNCPTR (gst_basic_scheduler_chainhandler_proxy); + } + else { + GST_DEBUG (GST_CAT_SCHEDULING, "setting cothreaded pull proxy for srcpad %s:%s\n", + GST_DEBUG_PAD_NAME (pad)); + GST_RPAD_GETHANDLER (pad) = GST_DEBUG_FUNCPTR (gst_basic_scheduler_gethandler_proxy); + GST_RPAD_PULLREGIONFUNC (pad) = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pullregionfunc_proxy); + } + } + } + + // need to set up the cothread now + if (wrapper_function != NULL) { + if (element->threadstate == NULL) { + // FIXME handle cothread_create returning NULL + element->threadstate = cothread_create (bin->threadcontext); + 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 (GST_CAT_SCHEDULING, "set wrapper function for '%s' to &%s\n", + GST_ELEMENT_NAME (element), GST_DEBUG_FUNCPTR_NAME (wrapper_function)); + } + } +} + +/* +G_GNUC_UNUSED static void +gst_basic_scheduler_chained_chain (GstBin *bin, _GstBinChain *chain) { + GList *elements; + GstElement *element; + GList *pads; + GstPad *pad; + + GST_DEBUG (GST_CAT_SCHEDULING,"chain entered\n"); + // walk through all the elements + elements = chain->elements; + while (elements) { + element = GST_ELEMENT (elements->data); + elements = g_list_next (elements); + + // walk through all the pads + pads = gst_element_get_pad_list (element); + while (pads) { + pad = GST_PAD (pads->data); + pads = g_list_next (pads); + if (!GST_IS_REAL_PAD(pad)) continue; + + if (GST_RPAD_DIRECTION(pad) == GST_PAD_SINK) { + GST_DEBUG (GST_CAT_SCHEDULING,"copying chain function into push proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad)); + GST_RPAD_CHAINHANDLER(pad) = GST_RPAD_CHAINFUNC(pad); + } else { + GST_DEBUG (GST_CAT_SCHEDULING,"copying get function into pull proxy for %s:%s\n",GST_DEBUG_PAD_NAME(pad)); + GST_RPAD_GETHANDLER(pad) = GST_RPAD_GETFUNC(pad); + GST_RPAD_PULLREGIONFUNC(pad) = GST_RPAD_GETREGIONFUNC(pad); + } + } + } +} +*/ + + +static GstSchedulerChain * +gst_basic_scheduler_chain_new (GstScheduler * sched) +{ + GstSchedulerChain *chain = g_new (GstSchedulerChain, 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 schedulers' 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; +} + +static void +gst_basic_scheduler_chain_destroy (GstSchedulerChain * chain) +{ + GstScheduler *sched = chain->sched; + + // remove the chain from the schedulers' 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); +} + +static void +gst_basic_scheduler_chain_add_element (GstSchedulerChain * 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++; +} + +static void +gst_basic_scheduler_chain_enable_element (GstSchedulerChain * 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_basic_scheduler_cothreaded_chain (GST_BIN (chain->sched->parent), chain); +} + +static void +gst_basic_scheduler_chain_disable_element (GstSchedulerChain * 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_basic_scheduler_cothreaded_chain(GST_BIN(chain->sched->parent),chain); +} + +static void +gst_basic_scheduler_chain_remove_element (GstSchedulerChain * 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_basic_scheduler_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_basic_scheduler_chain_destroy (chain); + + // unset the sched pointer for the element + element->sched = NULL; +} + +static void +gst_basic_scheduler_chain_elements (GstScheduler * sched, GstElement * element1, GstElement * element2) +{ + GList *chains; + GstSchedulerChain *chain; + GstSchedulerChain *chain1 = NULL, *chain2 = NULL; + GstElement *element; + + // first find the chains that hold the two + chains = sched->chains; + while (chains) { + chain = (GstSchedulerChain *) (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_basic_scheduler_chain_new (sched); + gst_basic_scheduler_chain_add_element (chain, element1); + gst_basic_scheduler_chain_add_element (chain, element2); + // FIXME chain changed here +// gst_basic_scheduler_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_basic_scheduler_cothreaded_chain(chain->sched->parent,chain); + + gst_basic_scheduler_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_basic_scheduler_chain_add_element (chain, element); + // FIXME chain changed here +// gst_basic_scheduler_cothreaded_chain(chain->sched->parent,chain); + } +} + + +// find the chain within the scheduler that holds the element, if any +static GstSchedulerChain * +gst_basic_scheduler_find_chain (GstScheduler * sched, GstElement * element) +{ + GList *chains; + GstSchedulerChain *chain; + + GST_INFO (GST_CAT_SCHEDULING, "searching for element \"%s\" in chains", + GST_ELEMENT_NAME (element)); + + chains = sched->chains; + while (chains) { + chain = (GstSchedulerChain *) (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; +} + +static void +gst_basic_scheduler_chain_recursive_add (GstSchedulerChain * chain, GstElement * element) +{ + GList *pads; + GstPad *pad; + GstElement *peerelement; + + // add the element to the chain + gst_basic_scheduler_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_basic_scheduler_find_chain (chain->sched, peerelement) == NULL) { + gst_basic_scheduler_chain_recursive_add (chain, peerelement); + } + } + } + } +} + +/* + * Entry points for this scheduler. + */ +static void +gst_basic_scheduler_add_element (GstScheduler * sched, GstElement * element) +{ + GList *pads; + GstPad *pad; + GstElement *peerelement; + GstSchedulerChain *chain; + + g_return_if_fail (element != NULL); + g_return_if_fail (GST_IS_ELEMENT (element)); + + // if it's already in this scheduler, don't bother doing anything + if (GST_ELEMENT_SCHED (element) == sched) + return; + + GST_INFO (GST_CAT_SCHEDULING, "adding element \"%s\" to scheduler", GST_ELEMENT_NAME (element)); + + // if the element already has a different scheduler, remove the element from it + if (GST_ELEMENT_SCHED (element)) { + gst_basic_scheduler_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_basic_scheduler_chain_new (sched); + gst_basic_scheduler_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 scheduler, chaining together"); + // make sure that the two elements are in the same chain + gst_basic_scheduler_chain_elements (sched, element, peerelement); + } + } + } +} + +static void +gst_basic_scheduler_remove_element (GstScheduler * sched, GstElement * element) +{ + GstSchedulerChain *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 scheduler", + GST_ELEMENT_NAME (element)); + + // find what chain the element is in + chain = gst_basic_scheduler_find_chain (sched, element); + + // remove it from its chain + gst_basic_scheduler_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; + } +} + +static void +gst_basic_scheduler_enable_element (GstScheduler *sched, GstElement *element) +{ + GstSchedulerChain *chain; + + // find the chain the element's in + chain = gst_basic_scheduler_find_chain (sched, element); + + if (chain) { + gst_basic_scheduler_chain_enable_element (chain, element); + } + else { + GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" not found in any chain, not enabling", GST_ELEMENT_NAME (element)); + } +} + +static void +gst_basic_scheduler_disable_element (GstScheduler *sched, GstElement *element) +{ + GstSchedulerChain *chain; + + // find the chain the element is in + chain = gst_basic_scheduler_find_chain (sched, element); + + // remove it from the chain + if (chain) { + gst_basic_scheduler_chain_disable_element (chain, element); + } + else { + GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" not found in any chain, not disabling", GST_ELEMENT_NAME (element)); + } +} + +static void +gst_basic_scheduler_lock_element (GstScheduler * sched, GstElement * element) +{ + if (element->threadstate) + cothread_lock (element->threadstate); +} + +static void +gst_basic_scheduler_unlock_element (GstScheduler * sched, GstElement * element) +{ + if (element->threadstate) + cothread_unlock (element->threadstate); +} + +static void +gst_basic_scheduler_pad_connect (GstScheduler * 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 scheduler, chaining together", + GST_DEBUG_PAD_NAME (sinkpad)); + gst_basic_scheduler_chain_elements (sched, srcelement, sinkelement); + } +} + +static void +gst_basic_scheduler_pad_disconnect (GstScheduler * sched, GstPad * srcpad, GstPad * sinkpad) +{ + GstSchedulerChain *chain; + GstElement *element1, *element2; + GstSchedulerChain *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_basic_scheduler_find_chain (sched, element1); + if (chain) { + GST_INFO (GST_CAT_SCHEDULING, "destroying chain"); + gst_basic_scheduler_chain_destroy (chain); + } + + // now create a new chain to hold element1 and build it from scratch + chain1 = gst_basic_scheduler_chain_new (sched); + gst_basic_scheduler_chain_recursive_add (chain1, element1); + + // check the other element to see if it landed in the newly created chain + if (gst_basic_scheduler_find_chain (sched, element2) == NULL) { + // if not in chain, create chain and build from scratch + chain2 = gst_basic_scheduler_chain_new (sched); + gst_basic_scheduler_chain_recursive_add (chain2, element2); + } +} + +static GstPad * +gst_basic_scheduler_pad_select (GstScheduler * sched, GList * padlist) +{ + GstPad *pad = NULL; + GList *padlist2 = padlist; + + GST_INFO (GST_CAT_SCHEDULING, "performing select"); + + while (padlist2) { + pad = GST_PAD (padlist2->data); + + if (gst_pad_peek (pad)) { + g_print ("found something in pad %s:%s\n", GST_DEBUG_PAD_NAME (pad)); + return pad; + } + + padlist2 = g_list_next (padlist2); + } + + /* else there is nothing ready to consume, set up the select functions */ + while (padlist) { + pad = GST_PAD (padlist->data); + + GST_RPAD_CHAINHANDLER (pad) = GST_DEBUG_FUNCPTR (gst_basic_scheduler_select_proxy); + + padlist = g_list_next (padlist); + } + if (pad != NULL) { + GstRealPad *peer = GST_RPAD_PEER (pad); + + cothread_switch (GST_ELEMENT (GST_PAD_PARENT (peer))->threadstate); + + g_print ("%p %s\n", GST_ELEMENT (GST_PAD_PARENT (pad)), + gst_element_get_name (GST_ELEMENT (GST_PAD_PARENT (pad)))); + pad = GST_ELEMENT (GST_PAD_PARENT (pad))->select_pad; + + g_assert (pad != NULL); + g_print ("back from select (%s:%s)\n", GST_DEBUG_PAD_NAME (pad)); + } + return pad; +} + +static gboolean +gst_basic_scheduler_iterate (GstScheduler * sched) +{ + GstBin *bin = GST_BIN (sched->parent); + GList *chains; + GstSchedulerChain *chain; + GstElement *entry; + gint num_basic_schedulerd = 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); + + // step through all the chains + chains = sched->chains; + + g_return_val_if_fail (chains != NULL, FALSE); + + while (chains) { + chain = (GstSchedulerChain *) (chains->data); + chains = g_list_next (chains); + + // 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_SCHEDULER (sched)->parent) != GST_STATE_VOID_PENDING) { + GST_DEBUG (GST_CAT_DATAFLOW, "handle pending state %d\n", + GST_STATE_PENDING (GST_SCHEDULER (sched)->parent)); + return FALSE; + } + + } + else { + GST_INFO (GST_CAT_DATAFLOW, "NO ENTRY INTO CHAIN!"); + eos = TRUE; + } + } + else { + GST_INFO (GST_CAT_DATAFLOW, "NO ENABLED ELEMENTS IN CHAIN!!"); + eos = TRUE; + } + } + + GST_DEBUG (GST_CAT_DATAFLOW, "leaving (%s)\n", GST_ELEMENT_NAME (bin)); + return !eos; +} + + +static void +gst_basic_scheduler_show (GstScheduler * sched) +{ + GList *chains, *elements; + GstElement *element; + GstSchedulerChain *chain; + + if (sched == NULL) { + g_print ("scheduler doesn't exist for this element\n"); + return; + } + + g_return_if_fail (GST_IS_SCHEDULER (sched)); + + g_print ("SCHEDULER DUMP FOR MANAGING BIN \"%s\"\n", GST_ELEMENT_NAME (sched->parent)); + + g_print ("scheduler 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 ("scheduler has %d chains in it\n", sched->num_chains); + chains = sched->chains; + while (chains) { + chain = (GstSchedulerChain *) (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/types/Makefile.am b/gst/types/Makefile.am index 7de9743a3b..4fb622b33d 100644 --- a/gst/types/Makefile.am +++ b/gst/types/Makefile.am @@ -2,7 +2,10 @@ filterdir = $(libdir)/gst filter_LTLIBRARIES = libgsttypes.la -libgsttypes_la_SOURCES = \ - gsttypes.c +libgsttypes_la_SOURCES = gsttypes.c + +libgsttypes_la_CFLAGS = $(XML_CFLAGS) $(XML_CFLAGS) $(GLIB_CFLAGS) + +libgsttypes_la_LIBADD = $(XML_LIBS) $(GLIB_LIBS) libgsttypes_la_LDFLAGS = -version-info $(GST_LIBVERSION) diff --git a/gstplay/Makefile.am b/gstplay/Makefile.am index b30d421cab..5efea227c0 100644 --- a/gstplay/Makefile.am +++ b/gstplay/Makefile.am @@ -2,8 +2,6 @@ # FIXME FIXME -LIBADD += $(GNOME_LIBS) $(GST_LIBS) -CFLAGS += $(GNOME_CFLAGS) $(LIBGLADE_GNOME_CFLAGS) $(GST_CFLAGS) -DDATADIR=\""$(gladedir)/"\" bin_PROGRAMS = gstmediaplay @@ -36,6 +34,6 @@ noinst_HEADERS = \ gstplayprivate.h libgstmediaplay_la_LDFLAGS = -rdynamic - -gstmediaplay_CFLAGS = $(LIBGLADE_GNOME_CFLAGS) +libgstmediaplay_la_CFLAGS = $(GNOME_CFLAGS) $(LIBGLADE_GNOME_CFLAGS) $(GST_CFLAGS) -DDATADIR=\""$(gladedir)/"\" +gstmediaplay_CFLAGS = $(LIBGLADE_GNOME_CFLAGS) $(GNOME_CFLAGS) $(LIBGLADE_GNOME_CFLAGS) $(GST_CFLAGS) -DDATADIR=\""$(gladedir)/"\" gstmediaplay_LDADD = $(GST_LIBS) $(LIBGLADE_GNOME_LIBS) libgstmediaplay.la diff --git a/gstplay/gstplay.c b/gstplay/gstplay.c index 42071c33f6..22d84cd9cc 100644 --- a/gstplay/gstplay.c +++ b/gstplay/gstplay.c @@ -147,6 +147,7 @@ gst_play_init (GstPlay *play) "sink"); } else { + GST_FLAG_SET (priv->video_element, GST_ELEMENT_THREAD_SUGGESTED); gst_bin_add (GST_BIN (priv->video_element), colorspace); gst_element_connect (colorspace, "src", priv->video_show, "sink"); gst_element_add_ghost_pad (priv->video_element, @@ -178,7 +179,11 @@ gst_play_new () static gboolean gst_play_idle_func (gpointer data) { - return gst_bin_iterate (GST_BIN (data)); + gboolean busy; + + busy = gst_bin_iterate (GST_BIN (data)); + + return busy; } static void diff --git a/libs/audio/Makefile.am b/libs/audio/Makefile.am index 355f3f5225..d9c76e22f8 100644 --- a/libs/audio/Makefile.am +++ b/libs/audio/Makefile.am @@ -8,4 +8,4 @@ libgstaudioincludedir = $(includedir)/gst/libs/gstaudio libgstaudioinclude_HEADERS = gstaudio.h # FIXME is this needed? -CFLAGS += -O2 $(FOMIT_FRAME_POINTER) -finline-functions -ffast-math +libgstaudio_la_CFLAGS = -O2 $(FOMIT_FRAME_POINTER) -finline-functions -ffast-math $(GLIB_CFLAGS) $(XML_CFLAGS) diff --git a/libs/bytestream/Makefile.am b/libs/bytestream/Makefile.am index 0a6e8ee9cf..a915640149 100644 --- a/libs/bytestream/Makefile.am +++ b/libs/bytestream/Makefile.am @@ -3,9 +3,10 @@ filterdir = $(libdir)/gst filter_LTLIBRARIES = libgstbytestream.la libgstbstest.la libgstbytestream_la_SOURCES = gstbytestream.c +libgstbytestream_la_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) libgstbstest_la_SOURCES = gstbstest.c +libgstbstest_la_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) libgstbytestreamincludedir = $(includedir)/gst/libs/bytestream libgstbytestreaminclude_HEADERS = gstbytestream.h -# CFLAGS += -O2 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math diff --git a/libs/control/Makefile.am b/libs/control/Makefile.am index 2c948cc199..c63537d85e 100644 --- a/libs/control/Makefile.am +++ b/libs/control/Makefile.am @@ -18,5 +18,4 @@ libgstcontrolinclude_HEADERS = \ gstdplinearinterp.h libgstcontrol_la_LIBADD = -lm - -CFLAGS += -O2 $(FOMIT_FRAME_POINTER) -finline-functions -ffast-math +libgstcontrol_la_CFLAGS = -O2 $(FOMIT_FRAME_POINTER) -finline-functions -ffast-math $(GLIB_CFLAGS) $(XML_CFLAGS) diff --git a/libs/getbits/Makefile.am b/libs/getbits/Makefile.am index f9f4699549..c96a6f45e9 100644 --- a/libs/getbits/Makefile.am +++ b/libs/getbits/Makefile.am @@ -21,4 +21,4 @@ check_PROGRAMS = gbtest gbtest_SOURCES = gbtest.c gbtest_LDADD = libgstgetbits.la $(GST_LIBS) -CFLAGS += -O2 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math +libgstgetbits_la_CFLAGS = -O2 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math $(GLIB_CFLAGS) $(XML_CFLAGS) diff --git a/libs/idct/Makefile.am b/libs/idct/Makefile.am index ba53d49080..44b476ae01 100644 --- a/libs/idct/Makefile.am +++ b/libs/idct/Makefile.am @@ -27,4 +27,4 @@ ieeetest_LDFLAGS = $(GNOME_LIBS) $(GST_LIBS) noinst_HEADERS = dct.h -CFLAGS += -O2 $(FOMIT_FRAME_POINTER) -finline-functions -ffast-math +libgstidct_la_CFLAGS = -O2 $(FOMIT_FRAME_POINTER) -finline-functions -ffast-math $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/libs/putbits/Makefile.am b/libs/putbits/Makefile.am index 727a1764bb..7bff65a602 100644 --- a/libs/putbits/Makefile.am +++ b/libs/putbits/Makefile.am @@ -9,4 +9,4 @@ libgstputbitsinclude_HEADERS = gstputbits.h noinst_HEADERS = gstputbits.h -CFLAGS += -O2 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math +libgstputbits_la_CFLAGS = -O2 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math diff --git a/libs/resample/Makefile.am b/libs/resample/Makefile.am index 504e9680d6..79893d080a 100644 --- a/libs/resample/Makefile.am +++ b/libs/resample/Makefile.am @@ -25,5 +25,5 @@ ARCHCFLAGS = endif endif -CFLAGS += -O2 -ffast-math $(ARCHCFLAGS) +libresample_la_CFLAGS = -O2 -ffast-math $(ARCHCFLAGS) diff --git a/libs/riff/Makefile.am b/libs/riff/Makefile.am index 6307536dba..493cd8381d 100644 --- a/libs/riff/Makefile.am +++ b/libs/riff/Makefile.am @@ -7,4 +7,4 @@ libgstriff_la_SOURCES = gstriffparse.c gstriffencode.c gstriffutil.c libgstriffincludedir = $(includedir)/gst/libs/gstriff libgstriffinclude_HEADERS = gstriff.h -CFLAGS += -O2 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math +libgstriff_la_CFLAGS = -O2 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/plugins/elements/Makefile.am b/plugins/elements/Makefile.am index 64b75fce5a..d9caf8310d 100644 --- a/plugins/elements/Makefile.am +++ b/plugins/elements/Makefile.am @@ -8,8 +8,6 @@ else GSTHTTPSRC= endif -#CFLAGS += -O2 -Wall -finstrument-functions -DGST_ENABLE_FUNC_INSTRUMENTATION - libgstelements_la_DEPENDENCIES = ../libgst.la libgstelements_la_SOURCES = \ gstelements.c \ @@ -43,8 +41,6 @@ noinst_HEADERS = \ gstaggregator.h \ gststatistics.h -CFLAGS += -O2 -Wall -LDFLAGS += -lm - -libgstelements_la_LIBADD = $(GHTTP_LIBS) +libgstelements_la_CFLAGS = $(GHTTP_CFLAGS) $(GLIB_CFLAGS) $(XML_CFLAGS) +libgstelements_la_LIBADD = $(GHTTP_LIBS) $(GLIB_LIBS) $(XML_LIBS) libgstelements_la_LDFLAGS = -version-info $(GST_LIBVERSION) diff --git a/plugins/elements/gstfakesink.c b/plugins/elements/gstfakesink.c index 02eb921fa3..69b8740525 100644 --- a/plugins/elements/gstfakesink.c +++ b/plugins/elements/gstfakesink.c @@ -213,14 +213,6 @@ gst_fakesink_get_property (GObject *object, guint prop_id, GValue *value, GParam } } -/** - * gst_fakesink_chain: - * @pad: the pad this faksink is connected to - * @buffer: the buffer or event that has to be absorbed - * - * Take the buffer or event from the pad and unref it without doing - * anything with it. - */ static void gst_fakesink_chain (GstPad *pad, GstBuffer *buf) { @@ -232,21 +224,12 @@ gst_fakesink_chain (GstPad *pad, GstBuffer *buf) fakesink = GST_FAKESINK (gst_pad_get_parent (pad)); - if (GST_IS_EVENT(buf)) { - GstEvent *event = GST_EVENT (buf); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - g_print("fakesink: have EOS event!\n"); - gst_element_set_state (GST_ELEMENT (fakesink), GST_STATE_PAUSED); - break; - default: - g_print("fakesink: have unhandled event!\n"); - break; - } - gst_event_free (event); + /* + if (GST_IS_EVENT (buf)) { + gst_pad_event_default (pad, GST_EVENT (buf)); return; } + */ if (!fakesink->silent) g_print("fakesink: chain ******* (%s:%s)< (%d bytes, %lld) %p\n", diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c index f78792d69a..cdad2e7aaf 100644 --- a/plugins/elements/gstqueue.c +++ b/plugins/elements/gstqueue.c @@ -265,6 +265,7 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf) reader = FALSE; +restart: /* we have to lock the queue since we span threads */ GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locking t:%ld\n", pthread_self ()); g_mutex_lock (queue->qlock); @@ -277,6 +278,8 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf) gst_queue_locked_flush (queue); break; case GST_EVENT_EOS: + GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "eos in on %s %d\n", + GST_ELEMENT_NAME (queue), queue->level_buffers); break; default: gst_pad_event_default (pad, GST_EVENT (buf)); @@ -327,19 +330,13 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf) 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_VOID_PENDING || -// GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING) -GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->sinkpad))))) != -GST_STATE_VOID_PENDING) - { + while (GST_STATE (queue) != GST_STATE_PLAYING) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n"); - if (GST_STATE_PENDING(queue) != GST_STATE_VOID_PENDING) - GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "GST_STATE_PENDING(queue) != GST_STATE_VOID_PENDING)\n"); - if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING) - GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING\n"); g_mutex_unlock (queue->qlock); cothread_switch(cothread_current_main()); + goto restart; } + g_assert (GST_STATE (queue) == GST_STATE_PLAYING); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for not_full, level:%d/%d\n", queue->level_buffers, queue->size_buffers); if (queue->writer) @@ -390,6 +387,7 @@ gst_queue_get (GstPad *pad) writer = FALSE; +restart: /* have to lock for thread-safety */ GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locking t:%ld\n", pthread_self ()); g_mutex_lock (queue->qlock); @@ -399,19 +397,13 @@ gst_queue_get (GstPad *pad) while (queue->level_buffers == 0) { // 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_VOID_PENDING || -// GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING) -GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->srcpad))))) != -GST_STATE_VOID_PENDING) - { + while (GST_STATE (queue) != GST_STATE_PLAYING) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n"); - if (GST_STATE_PENDING(queue) != GST_STATE_VOID_PENDING) - GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "GST_STATE_PENDING(queue) != GST_STATE_VOID_PENDING)\n"); - if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING) - GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_VOID_PENDING\n"); g_mutex_unlock (queue->qlock); cothread_switch(cothread_current_main()); + goto restart; } + g_assert (GST_STATE (queue) == GST_STATE_PLAYING); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for not_empty, level:%d/%d\n", queue->level_buffers, queue->size_buffers); if (queue->reader) @@ -451,7 +443,7 @@ GST_STATE_VOID_PENDING) GstEvent *event = GST_EVENT(buf); switch (GST_EVENT_TYPE(event)) { case GST_EVENT_EOS: - GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue eos\n"); + GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue \"%s\" eos\n", GST_ELEMENT_NAME (queue)); gst_element_set_state (GST_ELEMENT (queue), GST_STATE_PAUSED); break; default: @@ -467,56 +459,41 @@ gst_queue_change_state (GstElement *element) { GstQueue *queue; GstElementStateReturn ret; + GstElementState new_state; g_return_val_if_fail (GST_IS_QUEUE (element), GST_STATE_FAILURE); queue = GST_QUEUE (element); + GST_DEBUG_ENTER("('%s')", GST_ELEMENT_NAME (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); + g_mutex_lock (queue->qlock); - /* if going down into NULL state, clear out buffers*/ - if (GST_STATE_PENDING (element) == GST_STATE_READY) { - /* otherwise (READY or higher) we need to open the file */ - gst_queue_flush (queue); + new_state = GST_STATE_PENDING (element); + + if (new_state == GST_STATE_PAUSED) { + g_cond_signal (queue->not_full); + g_cond_signal (queue->not_empty); + } + else if (new_state == GST_STATE_READY) { + gst_queue_locked_flush (queue); + } + else if (new_state == GST_STATE_PLAYING) { + if (!GST_PAD_CONNECTED (queue->sinkpad)) { + // FIXME can this be? + if (queue->reader) + g_cond_signal (queue->not_empty); + g_mutex_unlock (queue->qlock); + + return GST_STATE_FAILURE; + } } - // if we haven't failed already, give the parent class a chance to ;-) - if (GST_ELEMENT_CLASS (parent_class)->change_state) - { - gboolean valid_handler = FALSE; - guint state_change_id = g_signal_lookup("state_change", G_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 && - g_signal_has_handler_pending(G_OBJECT(element), state_change_id, 0, FALSE)) - valid_handler = TRUE; - if (valid_handler) - g_signal_handler_block(G_OBJECT(element), state_change_id); - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); - - if (valid_handler) - g_signal_handler_unblock(G_OBJECT(element), state_change_id); - - // UNLOCK, *then* emit signal (if there's one there) - GST_UNLOCK(queue); - if (valid_handler) - g_signal_emit(G_OBJECT (element), state_change_id, 0, GST_STATE(element)); - } - else - { - ret = GST_STATE_SUCCESS; - GST_UNLOCK(queue); - } + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); + g_mutex_unlock (queue->qlock); + GST_DEBUG_LEAVE("('%s')", GST_ELEMENT_NAME (element)); return ret; } diff --git a/test/Makefile.am b/test/Makefile.am index 88ca16a9e9..5f062b4e0a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -4,7 +4,7 @@ if HAVE_GNOME GNOME_PROGS = spectrum wave mp1parse videotest aviparse \ videotest2 video2mp1 dvshow dv2mp1 \ mpeg2parse2 mpeg2parse3 \ - mp2tomp1v2 main sinesliders testspeed dvdplay + mp2tomp1v2 main sinesliders testspeed dvdplay testpod sinesliders_LDADD = ../libs/control/libgstcontrol.la else GNOME_PROGS = @@ -14,7 +14,7 @@ noinst_PROGRAMS = qtest $(GNOME_PROGS) record mp3 teardown buffer mp3parse \ mp3play ac3parse ac3play dvdcat fake cobin \ vidcapture avi2mpg mp2tomp1 mp1tomp1 pipetest \ vidcapture2 mp2toavi mp3tovorbis xmmstest \ - mp3mad lat + mp3mad lat SUBDIRS = xml bindings events memchunk @@ -24,7 +24,7 @@ ac3play_SOURCES = ac3play.c mem.c noinst_HEADERS = mem.h -LIBS += $(GNOME_LIBS) $(GST_LIBS) -CFLAGS += $(GNOME_CFLAGS) $(GST_CFLAGS) +LIBS = $(GNOME_LIBS) $(GST_LIBS) +CFLAGS = $(GNOME_CFLAGS) $(GST_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) EXTRA_DIST = README diff --git a/test/bindings/Makefile.am b/test/bindings/Makefile.am index 27542ace21..fdc7dc05f8 100644 --- a/test/bindings/Makefile.am +++ b/test/bindings/Makefile.am @@ -1,10 +1,10 @@ noinst_LTLIBRARIES = libcrashtest.la -libcrashtest_la_SOURCES = \ - dummy.c +libcrashtest_la_SOURCES = dummy.c +libcrashtest_la_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) -noinst_HEADERS = \ - dummy.h +noinst_HEADERS = dummy.h noinst_PROGRAMS = test -test_LDADD = libcrashtest.la +test_LDADD = libcrashtest.la $(GLIB_LIBS) +test_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/test/events/Makefile.am b/test/events/Makefile.am index f2300be1ac..82d65e2f46 100644 --- a/test/events/Makefile.am +++ b/test/events/Makefile.am @@ -1,4 +1,4 @@ noinst_PROGRAMS = seek -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GLIB_LIBS) $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/test/memchunk/Makefile.am b/test/memchunk/Makefile.am index e3198c289e..fdc2c40925 100644 --- a/test/memchunk/Makefile.am +++ b/test/memchunk/Makefile.am @@ -3,5 +3,5 @@ noinst_PROGRAMS = gmemchunktest gstmemchunktest gmemchunktest_SOURCES = gmemchunktest.c gstmemchunktest_SOURCES = gstmemchunktest.c gstmemchunk.c gstmemchunk.h -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/test/mpeg2parse2.c b/test/mpeg2parse2.c index 29f2d98d39..ae66fdf924 100644 --- a/test/mpeg2parse2.c +++ b/test/mpeg2parse2.c @@ -14,7 +14,7 @@ gboolean idle_func(gpointer data) { return TRUE; } -void mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) { +void mpegdemux_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) { g_print("***** a new pad %s was created %p\n", gst_pad_get_name(pad), pipeline); gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PAUSED); @@ -57,7 +57,7 @@ int main(int argc,char *argv[]) { } g_print("should be using file '%s'\n",argv[1]); - parse = gst_elementfactory_make("mpeg2parse","parse"); + parse = gst_elementfactory_make("mpegdemux","parse"); //parse = gst_elementfactory_make("mpeg1parse","parse"); g_return_val_if_fail(parse != NULL, -1); @@ -106,7 +106,7 @@ int main(int argc,char *argv[]) { gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(thread)); - gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad, pipeline); + gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpegdemux_newpad, pipeline); gtk_signal_connect(GTK_OBJECT(src),"eos",GTK_SIGNAL_FUNC(eof),NULL); diff --git a/test/mpeg2parse3.c b/test/mpeg2parse3.c index 75bf72736e..88d4f84d92 100644 --- a/test/mpeg2parse3.c +++ b/test/mpeg2parse3.c @@ -12,11 +12,10 @@ void eof(GstElement *src) { } gboolean idle_func(gpointer data) { - gst_bin_iterate(GST_BIN(data)); - return TRUE; + return gst_bin_iterate(GST_BIN(data)); } -void mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) { +void mpegdemux_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) { g_print("***** a new pad %s was created\n", gst_pad_get_name(pad)); @@ -31,7 +30,7 @@ void mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) { } } -void mpeg2parse_have_size(GstElement *videosink,gint width,gint height) { +void mpegdemux_have_size(GstElement *videosink,gint width,gint height) { gtk_widget_set_usize(gtk_socket,width,height); gtk_widget_show_all(appwindow); } @@ -54,7 +53,7 @@ int main(int argc,char *argv[]) { src = gst_elementfactory_make("dvdsrc","src"); g_print("using DVD source\n"); } else { - src = gst_elementfactory_make("disksrc","src"); + src = gst_elementfactory_make("filesrc","src"); } g_return_val_if_fail(src != NULL, -1); @@ -65,7 +64,7 @@ int main(int argc,char *argv[]) { } g_print("should be using file '%s'\n",argv[1]); - parse = gst_elementfactory_make("mpeg2parse","parse"); + parse = gst_elementfactory_make("mpegdemux","parse"); //parse = gst_elementfactory_make("mpeg1parse","parse"); g_return_val_if_fail(parse != NULL, -1); @@ -135,9 +134,9 @@ int main(int argc,char *argv[]) { gtk_socket_steal (GTK_SOCKET (gtk_socket), gst_util_get_int_arg (GTK_OBJECT(show), "xid")); - gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad, pipeline); + gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpegdemux_newpad, pipeline); gtk_signal_connect(GTK_OBJECT(src),"eos",GTK_SIGNAL_FUNC(eof),NULL); - gtk_signal_connect(GTK_OBJECT(show),"have_size",mpeg2parse_have_size, pipeline); + gtk_signal_connect(GTK_OBJECT(show),"have_size",mpegdemux_have_size, pipeline); g_print("setting to PLAYING state\n"); gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING); diff --git a/test/testpod.c b/test/testpod.c new file mode 100644 index 0000000000..07709fad14 --- /dev/null +++ b/test/testpod.c @@ -0,0 +1,86 @@ +#include +#include + +void play (GtkButton *button, gpointer data) +{ + gtk_signal_emit_by_name(GTK_OBJECT(data), "play"); +} + +void reset (GtkButton *button, gpointer data) +{ + gtk_signal_emit_by_name(GTK_OBJECT(data), "reset"); +} + +int main(int argc, char **argv) +{ + guint channels; + GtkWidget *window, *vbox, *play_button, *reset_button, *quit_button; + GstElement *disksrc, *mad, *stereo2mono, *pod, *osssink, *pipeline; + + gst_init (&argc, &argv); + gtk_init (&argc, &argv); + + if (argc!=2) { + g_print("usage: %s \n", argv[0]); + exit(-1); + } + + disksrc = gst_elementfactory_make("disksrc", "disksrc"); + mad = gst_elementfactory_make("mad", "mad"); + pod = gst_elementfactory_make("playondemand", "playondemand"); + osssink = gst_elementfactory_make("osssink", "osssink"); + + gtk_object_set(GTK_OBJECT(disksrc), "location", argv[1], NULL); + gtk_object_set(GTK_OBJECT(osssink), "fragment", 0x00180008, NULL); + gtk_object_get(GTK_OBJECT(disksrc), "channels", &channels, NULL); + + pipeline = gst_pipeline_new("app"); + + gst_bin_add(GST_BIN(pipeline), disksrc); + gst_bin_add(GST_BIN(pipeline), mad); + gst_bin_add(GST_BIN(pipeline), pod); + gst_bin_add(GST_BIN(pipeline), osssink); + + gst_element_connect(disksrc, "src", mad, "sink"); + gst_element_connect(pod, "src", osssink, "sink"); + + if (channels != 2) { + gst_element_connect(mad, "src", pod, "sink"); + } else { + stereo2mono = gst_elementfactory_make("stereo2mono", "stereo2mono"); + gst_bin_add(GST_BIN(pipeline), stereo2mono); + gst_element_connect(mad, "src", stereo2mono, "sink"); + gst_element_connect(stereo2mono, "src", pod, "sink"); + } + + gst_element_set_state(pipeline, GST_STATE_PLAYING); + + /* initialize gui elements ... */ + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + vbox = gtk_vbox_new(FALSE, 0); + play_button = gtk_button_new_with_label("play"); + reset_button = gtk_button_new_with_label("reset"); + quit_button = gtk_button_new_with_label("quit"); + + /* do the packing stuff ... */ + gtk_window_set_default_size(GTK_WINDOW(window), 96, 96); + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_box_pack_start(GTK_BOX(vbox), play_button, FALSE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(vbox), reset_button, FALSE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(vbox), quit_button, FALSE, FALSE, 2); + + /* connect things ... */ + gtk_signal_connect(GTK_OBJECT(play_button), "clicked", play, pod); + gtk_signal_connect(GTK_OBJECT(reset_button), "clicked", reset, pod); + gtk_signal_connect(GTK_OBJECT(quit_button), "clicked", gtk_main_quit, NULL); + + /* show the gui. */ + gtk_widget_show(play_button); + gtk_widget_show(reset_button); + gtk_widget_show(quit_button); + gtk_widget_show(vbox); + gtk_widget_show(window); + gtk_idle_add((GtkFunction)gst_bin_iterate, pipeline); + + gtk_main(); +} diff --git a/test/xml/Makefile.am b/test/xml/Makefile.am index 045355ec2e..2f9ac71747 100644 --- a/test/xml/Makefile.am +++ b/test/xml/Makefile.am @@ -1,5 +1,6 @@ noinst_PROGRAMS = readreg createreg LDADD = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) EXTRA_DIST = README diff --git a/tests/Makefile.am b/tests/Makefile.am index 43ac3402a0..9eeeb6f223 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -13,7 +13,7 @@ incsched reaping threadlock mp1vid reconnect \ faketest events timecache # we have nothing but apps here, we can do this safely -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) EXTRA_DIST = README diff --git a/tests/eos/Makefile.am b/tests/eos/Makefile.am index 55839b9e5a..aa55a8fcd5 100644 --- a/tests/eos/Makefile.am +++ b/tests/eos/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = case1 case2 case3 case4 case5 case6 case7 # jsut apps here, this is safe -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/incsched.c b/tests/incsched.c index 1e63534ad3..edb73f88a4 100644 --- a/tests/incsched.c +++ b/tests/incsched.c @@ -19,108 +19,108 @@ int main(int argc,char *argv[]) { g_print("\nAdding src to thread:\n"); gst_bin_add(thread,src); - gst_schedule_show(GST_ELEMENT_SCHED(thread)); + gst_scheduler_show(GST_ELEMENT_SCHED(thread)); g_print("\nAdding identity to thread:\n"); gst_bin_add(thread,identity); - gst_schedule_show(GST_ELEMENT_SCHED(thread)); + gst_scheduler_show(GST_ELEMENT_SCHED(thread)); g_print("\nRemoving identity from thread:\n"); gst_bin_remove(thread, identity); - gst_schedule_show(GST_ELEMENT_SCHED(thread)); + gst_scheduler_show(GST_ELEMENT_SCHED(thread)); g_print("\nAdding identity to thread:\n"); gst_bin_add(thread,identity); - gst_schedule_show(GST_ELEMENT_SCHED(thread)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_show(GST_ELEMENT_SCHED(thread)); g_print("\nAdding sink to bin:\n"); gst_bin_add(bin,sink); - gst_schedule_show(GST_ELEMENT_SCHED(thread)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_show(GST_ELEMENT_SCHED(thread)); g_print("\nDisconnecting sink:\n"); gst_element_disconnect(identity,"src",sink,"sink"); - gst_schedule_show(GST_ELEMENT_SCHED(thread)); + gst_scheduler_show(GST_ELEMENT_SCHED(thread)); g_print("\nAdding identity2 to bin:\n"); gst_bin_add(bin, identity2); - gst_schedule_show(GST_ELEMENT_SCHED(thread)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_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)); + gst_scheduler_show(GST_ELEMENT_SCHED(thread)); g_print("\n\nIterating:\n"); gst_bin_iterate(thread); diff --git a/tests/mp1vid.c b/tests/mp1vid.c index 678f2f31f9..c502b1bc29 100644 --- a/tests/mp1vid.c +++ b/tests/mp1vid.c @@ -59,7 +59,7 @@ int main(int argc,char *argv[]) { gst_bin_add(GST_BIN(pipeline),sourcethread); - gst_schedule_show(GST_ELEMENT_SCHED(pipeline)); + gst_scheduler_show(GST_ELEMENT_SCHED(pipeline)); gst_element_set_state(pipeline,GST_STATE_PLAYING); sleep(1); diff --git a/tests/muxing/Makefile.am b/tests/muxing/Makefile.am index 5b25390e24..447ed2f940 100644 --- a/tests/muxing/Makefile.am +++ b/tests/muxing/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = case1 # jsut apps here, this is safe -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/nego/Makefile.am b/tests/nego/Makefile.am index 4260472389..7e47fff9b6 100644 --- a/tests/nego/Makefile.am +++ b/tests/nego/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = nego1 # jsut apps here, this is safe -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/autoplug/Makefile.am b/tests/old/examples/autoplug/Makefile.am index f263f27100..8f8cdd4153 100644 --- a/tests/old/examples/autoplug/Makefile.am +++ b/tests/old/examples/autoplug/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = autoplug # just an app here, we're safe -LIBS += $(GNOME_LIBS) $(GST_LIBS) -CFLAGS += $(GNOME_CFLAGS) $(GST_CFLAGS) +autoplug_LDADD = $(GNOME_LIBS) $(GST_LIBS) $(GLIB_LIBS) +autoplug_CFLAGS = $(GNOME_CFLAGS) $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/cutter/Makefile.am b/tests/old/examples/cutter/Makefile.am index c1fca3f985..29da841f05 100644 --- a/tests/old/examples/cutter/Makefile.am +++ b/tests/old/examples/cutter/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = cutter noinst_HEADERS = cutter.h -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +cutter_LDADD = $(GST_LIBS) +cutter_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/helloworld/Makefile.am b/tests/old/examples/helloworld/Makefile.am index 77e8ef336a..5821f461f2 100644 --- a/tests/old/examples/helloworld/Makefile.am +++ b/tests/old/examples/helloworld/Makefile.am @@ -1,4 +1,4 @@ noinst_PROGRAMS = helloworld -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +helloworld_LDADD = $(GST_LIBS) +helloworld_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/helloworld2/Makefile.am b/tests/old/examples/helloworld2/Makefile.am index 6d686a4092..1daf5c0da1 100644 --- a/tests/old/examples/helloworld2/Makefile.am +++ b/tests/old/examples/helloworld2/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = helloworld2 -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +helloworld2_LDADD = $(GST_LIBS) +helloworld2_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/launch/Makefile.am b/tests/old/examples/launch/Makefile.am index 11c2e57cfc..c1d844569c 100644 --- a/tests/old/examples/launch/Makefile.am +++ b/tests/old/examples/launch/Makefile.am @@ -1,8 +1,8 @@ noinst_PROGRAMS = mp3parselaunch # just an app here, we're safe -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +mp3parselaunch_LDADD = $(GST_LIBS) +mp3parselaunch_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) noinst_SCRIPTS = mp3play EXTRA_DIST = mp3play diff --git a/tests/old/examples/mixer/Makefile.am b/tests/old/examples/mixer/Makefile.am index d15b425208..8d993da8c7 100644 --- a/tests/old/examples/mixer/Makefile.am +++ b/tests/old/examples/mixer/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = mixer noinst_HEADERS = mixer.h -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +mixer_LDADD = $(GST_LIBS) +mixer_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/mixer/mixer.c b/tests/old/examples/mixer/mixer.c index 7a02eddcb4..ec492cad34 100644 --- a/tests/old/examples/mixer/mixer.c +++ b/tests/old/examples/mixer/mixer.c @@ -190,7 +190,7 @@ int main(int argc,char *argv[]) gst_element_set_state(main_bin, GST_STATE_PLAYING); // write out the schedule - gst_schedule_show(GST_ELEMENT_SCHED(main_bin)); + gst_scheduler_show(GST_ELEMENT_SCHED(main_bin)); playing = TRUE; j = 0; diff --git a/tests/old/examples/plugins/Makefile.am b/tests/old/examples/plugins/Makefile.am index 5e0b9fca0f..11c631711d 100644 --- a/tests/old/examples/plugins/Makefile.am +++ b/tests/old/examples/plugins/Makefile.am @@ -1,4 +1,5 @@ noinst_LTLIBRARIES = libexample.la libexample_la_SOURCES = example.c +libexample_la_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) noinst_HEADERS = example.h diff --git a/tests/old/examples/queue/Makefile.am b/tests/old/examples/queue/Makefile.am index e4ef4c7ce8..7b67eeabd6 100644 --- a/tests/old/examples/queue/Makefile.am +++ b/tests/old/examples/queue/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = queue -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +queue_LDADD = $(GST_LIBS) +queue_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/queue2/Makefile.am b/tests/old/examples/queue2/Makefile.am index fd4f914bbd..5bd7542f1c 100644 --- a/tests/old/examples/queue2/Makefile.am +++ b/tests/old/examples/queue2/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = queue2 -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +queue2_LDADD = $(GST_LIBS) +queue2_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/queue3/Makefile.am b/tests/old/examples/queue3/Makefile.am index be6313ce6d..de2d00faab 100644 --- a/tests/old/examples/queue3/Makefile.am +++ b/tests/old/examples/queue3/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = queue3 -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +queue3_LDADD = $(GST_LIBS) +queue3_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/queue4/Makefile.am b/tests/old/examples/queue4/Makefile.am index 0b1a4857b8..8d6e2eec95 100644 --- a/tests/old/examples/queue4/Makefile.am +++ b/tests/old/examples/queue4/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = queue4 -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +queue4_LDADD = $(GST_LIBS) +queue4_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/thread/Makefile.am b/tests/old/examples/thread/Makefile.am index 4e019cb731..ae9f9ac759 100644 --- a/tests/old/examples/thread/Makefile.am +++ b/tests/old/examples/thread/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = thread -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +thread_LDADD = $(GST_LIBS) +thread_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/typefind/Makefile.am b/tests/old/examples/typefind/Makefile.am index 57669bdcc0..e8a9b4f1c8 100644 --- a/tests/old/examples/typefind/Makefile.am +++ b/tests/old/examples/typefind/Makefile.am @@ -1,5 +1,5 @@ noinst_PROGRAMS = typefind -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +typefind_LDADD = $(GST_LIBS) +typefind_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/examples/xml/Makefile.am b/tests/old/examples/xml/Makefile.am index 24b890fd84..7b8e2f4745 100644 --- a/tests/old/examples/xml/Makefile.am +++ b/tests/old/examples/xml/Makefile.am @@ -1,5 +1,7 @@ noinst_PROGRAMS = createxml runxml -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +createxml_LDADD = $(GST_LIBS) +createxml_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) +runxml_LDADD = $(GST_LIBS) +runxml_CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/testsuite/Makefile.am b/tests/old/testsuite/Makefile.am index 74d5101862..e5d82ee00a 100644 --- a/tests/old/testsuite/Makefile.am +++ b/tests/old/testsuite/Makefile.am @@ -8,8 +8,8 @@ TESTS = $(testprogs) check_PROGRAMS = $(testprogs) # we have nothing but apps here, we can do this safely -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) DIST_SUBDIRS = refcounting capsnego plugin bytestream diff --git a/tests/old/testsuite/bytestream/Makefile.am b/tests/old/testsuite/bytestream/Makefile.am index 75aeed7915..1f617b231f 100644 --- a/tests/old/testsuite/bytestream/Makefile.am +++ b/tests/old/testsuite/bytestream/Makefile.am @@ -9,5 +9,5 @@ test1_LDFLAGS = -L$(top_builddir)/libs/bytestream/ -lgstbytestream # we have nothing but apps here, we can do this safely -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/testsuite/capsnego/Makefile.am b/tests/old/testsuite/capsnego/Makefile.am index 6b1c466c7c..8dc74bb8c0 100644 --- a/tests/old/testsuite/capsnego/Makefile.am +++ b/tests/old/testsuite/capsnego/Makefile.am @@ -5,5 +5,5 @@ TESTS = $(testprogs) check_PROGRAMS = $(testprogs) # we have nothing but apps here, we can do this safely -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/testsuite/dynparams/Makefile.am b/tests/old/testsuite/dynparams/Makefile.am index f56298f1cc..bc7386fe1c 100644 --- a/tests/old/testsuite/dynparams/Makefile.am +++ b/tests/old/testsuite/dynparams/Makefile.am @@ -10,4 +10,4 @@ dparamstest_SOURCES = dparamstest.c dparamstest_LDFLAGS = -L$(top_builddir)/libs/control/ -lgstcontrol # we have nothing but apps here, we can do this safely LIBS = $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/testsuite/plugin/Makefile.am b/tests/old/testsuite/plugin/Makefile.am index 9acef8767d..4cadb77724 100644 --- a/tests/old/testsuite/plugin/Makefile.am +++ b/tests/old/testsuite/plugin/Makefile.am @@ -16,5 +16,5 @@ TESTS = $(testprogs) check_PROGRAMS = $(testprogs) # we have nothing but apps here, we can do this safely -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/old/testsuite/refcounting/Makefile.am b/tests/old/testsuite/refcounting/Makefile.am index 06319a7597..3d98225aa8 100644 --- a/tests/old/testsuite/refcounting/Makefile.am +++ b/tests/old/testsuite/refcounting/Makefile.am @@ -16,6 +16,6 @@ EXTRA_DIST = thread.c object.c element.c element_pad.c bin.c noinst_HEADERS = mem.h # we have nothing but apps here, we can do this safely -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tests/sched/Makefile.am b/tests/sched/Makefile.am index 2bcb8cee39..8f1fa53d6a 100644 --- a/tests/sched/Makefile.am +++ b/tests/sched/Makefile.am @@ -7,5 +7,5 @@ endif dynamic_pipeline_SOURCES = dynamic-pipeline.c # nothing but apps here, this is safe -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index 74d5101862..e5d82ee00a 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -8,8 +8,8 @@ TESTS = $(testprogs) check_PROGRAMS = $(testprogs) # we have nothing but apps here, we can do this safely -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) DIST_SUBDIRS = refcounting capsnego plugin bytestream diff --git a/testsuite/bytestream/Makefile.am b/testsuite/bytestream/Makefile.am index 75aeed7915..1f617b231f 100644 --- a/testsuite/bytestream/Makefile.am +++ b/testsuite/bytestream/Makefile.am @@ -9,5 +9,5 @@ test1_LDFLAGS = -L$(top_builddir)/libs/bytestream/ -lgstbytestream # we have nothing but apps here, we can do this safely -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/testsuite/capsnego/Makefile.am b/testsuite/capsnego/Makefile.am index 6b1c466c7c..8dc74bb8c0 100644 --- a/testsuite/capsnego/Makefile.am +++ b/testsuite/capsnego/Makefile.am @@ -5,5 +5,5 @@ TESTS = $(testprogs) check_PROGRAMS = $(testprogs) # we have nothing but apps here, we can do this safely -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/testsuite/dynparams/Makefile.am b/testsuite/dynparams/Makefile.am index f56298f1cc..bc7386fe1c 100644 --- a/testsuite/dynparams/Makefile.am +++ b/testsuite/dynparams/Makefile.am @@ -10,4 +10,4 @@ dparamstest_SOURCES = dparamstest.c dparamstest_LDFLAGS = -L$(top_builddir)/libs/control/ -lgstcontrol # we have nothing but apps here, we can do this safely LIBS = $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/testsuite/plugin/Makefile.am b/testsuite/plugin/Makefile.am index 9acef8767d..4cadb77724 100644 --- a/testsuite/plugin/Makefile.am +++ b/testsuite/plugin/Makefile.am @@ -16,5 +16,5 @@ TESTS = $(testprogs) check_PROGRAMS = $(testprogs) # we have nothing but apps here, we can do this safely -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/testsuite/refcounting/Makefile.am b/testsuite/refcounting/Makefile.am index 06319a7597..3d98225aa8 100644 --- a/testsuite/refcounting/Makefile.am +++ b/testsuite/refcounting/Makefile.am @@ -16,6 +16,6 @@ EXTRA_DIST = thread.c object.c element.c element_pad.c bin.c noinst_HEADERS = mem.h # we have nothing but apps here, we can do this safely -LIBS += $(GST_LIBS) -CFLAGS += $(GST_CFLAGS) +LIBS = $(GST_LIBS) +CFLAGS = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS) diff --git a/tools/Makefile.am b/tools/Makefile.am index bef06f9476..a761fd77dc 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -28,6 +28,6 @@ man_MANS = gstreamer-launch.1 gstreamer-register.1 gstreamer-inspect.1 \ gstreamer-complete.1 gstreamer-compprep.1 LDADD = $(GST_LIBS) -CFLAGS = $(LIBGST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" +CFLAGS = $(GST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" $(GLIB_CFLAGS) $(XML_CFLAGS) EXTRA_DIST = $(man_MANS) diff --git a/tools/gstreamer-inspect.c b/tools/gstreamer-inspect.c index 6ac84be18a..423516a698 100644 --- a/tools/gstreamer-inspect.c +++ b/tools/gstreamer-inspect.c @@ -440,6 +440,12 @@ print_element_list (void) if (factory->typefindfunc) printf(" Has typefind function: %s\n",GST_DEBUG_FUNCPTR_NAME(factory->typefindfunc)); } + else if (GST_IS_SCHEDULERFACTORY (feature)) { + GstSchedulerFactory *factory; + + factory = GST_SCHEDULERFACTORY (feature); + printf("%s: %s: %s\n", plugin->name, GST_OBJECT_NAME (factory), factory->longdesc); + } else { printf("%s: %s (%s)\n", plugin->name, gst_object_get_name (GST_OBJECT (feature)), g_type_name (G_OBJECT_TYPE (feature))); @@ -489,6 +495,12 @@ print_plugin_info (GstPlugin *plugin) if (factory->typefindfunc) printf(" Has typefind function: %s\n",GST_DEBUG_FUNCPTR_NAME(factory->typefindfunc)); } + else if (GST_IS_SCHEDULERFACTORY (feature)) { + GstSchedulerFactory *factory; + + factory = GST_SCHEDULERFACTORY (feature); + printf(" %s: %s\n", GST_OBJECT_NAME (factory), factory->longdesc); + } else { printf(" %s (%s)\n", gst_object_get_name (GST_OBJECT (feature)), g_type_name (G_OBJECT_TYPE (feature))); diff --git a/tools/gstreamer-launch.c b/tools/gstreamer-launch.c index 8e91fc05ce..e50db14cbd 100644 --- a/tools/gstreamer-launch.c +++ b/tools/gstreamer-launch.c @@ -65,6 +65,7 @@ idle_func (gpointer data) #ifndef USE_GLIB2 gtk_main_quit (); #endif + g_print ("iteration ended\n"); return FALSE; } return TRUE;