Merged from INCSCHED on 200505251!!!

Original commit message from CVS:
Merged from INCSCHED on 200505251!!!
This commit is contained in:
Erik Walthinsen 2001-05-25 21:00:07 +00:00
parent 54271eca8e
commit 4a583683e5
111 changed files with 8357 additions and 1740 deletions

2
.gitignore vendored
View file

@ -11,6 +11,8 @@ config.sub
configure configure
gstreamer-[0-9]* gstreamer-[0-9]*
gstreamer-config gstreamer-config
gstreamer.pc
gstreamer-uninstalled.pc
gstreamer.spec gstreamer.spec
libtool libtool
ltconfig ltconfig

View file

@ -3,6 +3,8 @@ Matt Howell <mhowell@users.sourceforge.net>
Brent Bradburn <bbradburn@users.sourceforge.net> Brent Bradburn <bbradburn@users.sourceforge.net>
Wim Taymans <wim.taymans@tvd.be> Wim Taymans <wim.taymans@tvd.be>
Richard Boulton <richard@tartarus.org> Richard Boulton <richard@tartarus.org>
Zaheer Merali <zaheer@grid9.net>
- thread synchronization rework
David I. Lehn <dlehn@users.sourceforge.net> David I. Lehn <dlehn@users.sourceforge.net>
- debian packaging - debian packaging
- various fixes - various fixes

View file

@ -26,9 +26,14 @@ bin_SCRIPTS = gstreamer-config
m4datadir = $(datadir)/aclocal m4datadir = $(datadir)/aclocal
m4data_DATA = gstreamer.m4 m4data_DATA = gstreamer.m4
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = gstreamer.pc
man_MANS = gstreamer-config.1 man_MANS = gstreamer-config.1
EXTRA_DIST = gstreamer.spec.in gstreamer-config.in gstreamer.m4 LICENSE REQUIREMENTS $(man_MANS) EXTRA_DIST = gstreamer.spec.in gstreamer-config.in gstreamer.m4 \
gstreamer.pc.in gstreamer-uninstall.pc.in \
LICENSE REQUIREMENTS ABOUT-NLS $(man_MANS)
dist-hook: dist-hook:
cp gstreamer.spec $(distdir) cp gstreamer.spec $(distdir)

View file

@ -79,24 +79,9 @@ autoheader
autoconf autoconf
automake --add-missing automake --add-missing
if [ "x$1" = "x--autogen-recurse" ];then
exit # the rest will happen later
fi
#for dir in `find * -name autogen.sh -print | grep -v '^autogen.sh$' | \
# sed 's/autogen.sh$//'`;do
# echo "Recursively running autogen.sh in $dir"
# pushd $dir > /dev/null
# ./autogen.sh --autogen-recurse "$@"
# popd > /dev/null
#done
# now remove the cache, because it can be considered dangerous in this case # now remove the cache, because it can be considered dangerous in this case
rm -f config.cache rm -f config.cache
# For busy application developers (Hadess)
# ./configure --enable-maintainer-mode --enable-debug --enable-debug-verbose --disable-docs-build "$@"
./configure --enable-maintainer-mode --enable-plugin-srcdir --enable-debug --enable-debug-verbose "$@" ./configure --enable-maintainer-mode --enable-plugin-srcdir --enable-debug --enable-debug-verbose "$@"
echo echo

View file

@ -417,35 +417,75 @@ AC_SUBST(X_LIBS)
dnl Check for the Xv library dnl Check for the Xv library
xvsave_LIBS=${LIBS} xvsave_LIBS=${LIBS}
AC_CHECK_LIB(Xv, XvQueryExtension, HAVE_LIBXV=yes, HAVE_LIBXV=no, $X_LIBS $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS) AC_CHECK_LIB(Xv, XvQueryExtension,
HAVE_LIBXV=yes
AC_DEFINE(HAVE_LIBXV),
HAVE_LIBXV=no,
$X_LIBS $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS
)
LIBS=${xvsave_LIBS} LIBS=${xvsave_LIBS}
AC_CHECK_HEADER(X11/extensions/Xv.h, :, HAVE_LIBXV=no) AC_CHECK_HEADER(X11/extensions/Xv.h, :, HAVE_LIBXV=no)
AC_CHECK_HEADER(X11/extensions/Xvlib.h, :, HAVE_LIBXV=no) AC_CHECK_HEADER(X11/extensions/Xvlib.h, :, HAVE_LIBXV=no)
dnl Check for OSS audio dnl Check for OSS audio
AC_CHECK_HEADER(sys/soundcard.h, HAVE_OSS=yes, HAVE_OSS=no) AC_CHECK_HEADER(sys/soundcard.h,
AC_DEFINE(HAVE_OSS)
HAVE_OSS=yes, []
)
dnl Check for xaudio dnl Check for xaudio
AC_CHECK_HEADER(xaudio/decoder.h, HAVE_XAUDIO=yes, HAVE_XAUDIO=no) AC_CHECK_HEADER(xaudio/decoder.h,
AC_DEFINE(HAVE_XAUDIO)
HAVE_XAUDIO="yes",
AC_MSG_WARN(
***** NOTE: These plugins won't be built: gstxa
)
HAVE_XAUDIO="no",
)
dnl Check for libmad dnl Check for libmad
AC_MSG_CHECKING(MAD library) AC_MSG_CHECKING(MAD library)
AC_CHECK_LIB(mad, mad_decoder_finish, HAVE_LIBMAD=yes, HAVE_LIBMAD=no, ) AC_CHECK_LIB(mad, mad_decoder_finish,
AC_CHECK_HEADER(mad.h, :, HAVE_LIBMAD=no) HAVE_LIBMAD=yes
AC_DEFINE(HAVE_LIBMAD),
AC_MSG_WARN(
***** NOTE: These plugins won't be built: mad
)
HAVE_LIBMAD=no,
)
dnl Check for libvorbis dnl Check for libvorbis
AC_MSG_CHECKING(Vorbis library) AC_MSG_CHECKING(Vorbis library)
AC_CHECK_LIB(vorbis, ogg_sync_init, HAVE_VORBIS=yes, HAVE_VORBIS=no, ) AC_CHECK_LIB(vorbis, ogg_sync_init,
AC_CHECK_HEADER(vorbis/codec.h, :, HAVE_VORBIS=no) HAVE_VORBIS=yes
AC_DEFINE(HAVE_VORBIS),
AC_MSG_WARN(
***** NOTE: These plugins won't be built: vorbisdec vorbisenc
)
HAVE_VORBIS=no,
)
dnl Check for libjpeg dnl Check for libjpeg
AC_MSG_CHECKING(libjpeg library) AC_MSG_CHECKING(libjpeg library)
AC_CHECK_LIB(jpeg, jpeg_set_defaults, HAVE_LIBJPEG=yes, HAVE_LIBJPEG=no, ) AC_CHECK_LIB(jpeg, jpeg_set_defaults,
AC_CHECK_HEADER(jpeglib.h, :, HAVE_LIBJPEG=no) HAVE_LIBJPEG=yes
AC_DEFINE(HAVE_LIBJPEG),
AC_MSG_WARN(
***** NOTE: These plugins won't be built: jpegdec jpegenc
)
HAVE_LIBJPEG=no,
)
dnl Check for libHermes dnl Check for Hermes
AC_MSG_CHECKING(Hermes library) AC_MSG_CHECKING(Hermes library)
AC_CHECK_LIB(Hermes, Hermes_ConverterInstance, HAVE_LIBHERMES=yes, HAVE_LIBHERMES=no, ) AC_CHECK_LIB(Hermes, Hermes_ConverterInstance,
HAVE_LIBHERMES=yes
AC_DEFINE(HAVE_LIBHERMES),
AC_MSG_WARN(
***** NOTE: These plugins won't be built: colorspace
)
HAVE_LIBHERMES=no,
)
AC_CHECK_HEADER(Hermes/Hermes.h, :, HAVE_LIBHERMES=no) AC_CHECK_HEADER(Hermes/Hermes.h, :, HAVE_LIBHERMES=no)
dnl Check for cdparanoia dnl Check for cdparanoia
@ -672,13 +712,13 @@ esac],
[:]) dnl Default value [:]) dnl Default value
AC_ARG_ENABLE(docs-build, AC_ARG_ENABLE(docs-build,
[ --disable-docs-build disable all building of documentation], [ --enable-docs-build enable building of documentation],
[case "${enableval}" in [case "${enableval}" in
yes) BUILD_DOCS=yes ;; yes) BUILD_DOCS=yes ;;
no) BUILD_DOCS=no ;; no) BUILD_DOCS=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-docs-build) ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-docs-build) ;;
esac], esac],
[BUILD_DOCS=yes]) dnl Default value [BUILD_DOCS=no]) dnl Default value
AC_ARG_ENABLE(plugin-docs, AC_ARG_ENABLE(plugin-docs,
[ --enable-plugin-docs enable the building of plugin documentation [ --enable-plugin-docs enable the building of plugin documentation
@ -889,7 +929,11 @@ dnl ##############################
dnl # Set up the defaults cflags # dnl # Set up the defaults cflags #
dnl ############################## dnl ##############################
dnl CC="kgcc" dnl CC="kgcc"
CFLAGS="$CORE_CFLAGS $CFLAGS -O6 -Wall" if test "x$USE_PROFILING" = xyes; then
CFLAGS="$CORE_CFLAGS $CFLAGS -Wall"
else
CFLAGS="$CORE_CFLAGS $CFLAGS -O6 -Wall"
fi
LIBS="$CORE_LIBS $LIBS" LIBS="$CORE_LIBS $LIBS"
AC_SUBST(CORE_LIBS) AC_SUBST(CORE_LIBS)
AC_SUBST(CORE_CFLAGS) AC_SUBST(CORE_CFLAGS)
@ -1041,6 +1085,7 @@ tests/Makefile
tests/sched/Makefile tests/sched/Makefile
tests/eos/Makefile tests/eos/Makefile
testsuite/Makefile testsuite/Makefile
testsuite/refcounting/Makefile
testsuite/capsnego/Makefile testsuite/capsnego/Makefile
tests/nego/Makefile tests/nego/Makefile
examples/Makefile examples/Makefile
@ -1073,5 +1118,7 @@ docs/fwg/Makefile
debian/Makefile debian/Makefile
stamp.h stamp.h
gstreamer-config gstreamer-config
gstreamer.spec]) gstreamer.spec
gstreamer.pc
gstreamer-uninstalled.pc])
AC_OUTPUT_COMMANDS([chmod +x gstreamer-config]) AC_OUTPUT_COMMANDS([chmod +x gstreamer-config])

View file

@ -61,9 +61,9 @@ The maximum number of cothreads we are going to support.
@argv: @argv:
@flags: @flags:
@sp: @sp:
@jmp:
@top_sp: @top_sp:
@pc: @pc:
@jmp:
<!-- ##### STRUCT cothread_context ##### --> <!-- ##### STRUCT cothread_context ##### -->
<para> <para>

View file

@ -267,24 +267,6 @@ circumstances.
@Returns: @Returns:
<!-- ##### FUNCTION gst_element_set_manager ##### -->
<para>
</para>
@element:
@manager:
<!-- ##### FUNCTION gst_element_get_manager ##### -->
<para>
</para>
@element:
@Returns:
<!-- ##### FUNCTION gst_element_set_parent ##### --> <!-- ##### FUNCTION gst_element_set_parent ##### -->
<para> <para>

View file

@ -46,3 +46,8 @@ The <classname>GstFakeSrc</classname> generates empty buffers. (fakesrc)
</para> </para>
<!-- ##### ARG GstFakeSrc:eos ##### -->
<para>
</para>

View file

@ -24,8 +24,10 @@ Thread flags:
</para> </para>
@GST_THREAD_CREATE: The thread is being created. @GST_THREAD_CREATE: The thread is being created.
@GST_THREAD_STATE_STARTED:
@GST_THREAD_STATE_SPINNING: The thread is runnning @GST_THREAD_STATE_SPINNING: The thread is runnning
@GST_THREAD_STATE_REAPING: The thread is ending. @GST_THREAD_STATE_REAPING: The thread is ending.
@GST_THREAD_STATE_ELEMENT_CHANGED:
@GST_THREAD_FLAG_LAST: subclass use this to start their enumeration @GST_THREAD_FLAG_LAST: subclass use this to start their enumeration
<!-- ##### STRUCT GstThread ##### --> <!-- ##### STRUCT GstThread ##### -->

View file

@ -0,0 +1,125 @@
-----------------------------------------------------------
- GStreamer Scheduling / Synchronization (incsched) Notes -
-----------------------------------------------------------
These notes describe deadlock scenarios and proposed solutions for
GStreamer. This will be implemented in the INCSCHED1 branch.
I. Miscelaneous proposals
II. Liveness problems (sometimes deadlock ;) and propsed solutions
III. State transition approach and responsibility
MattH.
--------------------------------
- I. Miscalenous proposals -
--------------------------------
1. Change the names of GstThread and GstQueue to GstPtThread and GstPtQueue
for pthread versions of Thread and Queue.
2. Change GstPtQueue to check its pads' peers' managers and make sure
they are different. If not, fail and generate error message. (This
ensures a GstPtQueue straddles a pthread boundary.)
3. Change state transitions to NULL <-> READY <-> PAUSED <-> PLAYING.
---------------------------------------------------
- II. Deadlock Scenarios and Proposed Solutions -
- (in the order they will be implemented) -
---------------------------------------------------
1. A downstream element "waits" for a buffer from its upstream element,
a state change happens and "pauses" the upstream element -- the
downstream element is blocked and cannot execute its change_state.
Note that this can only happen within a single GstPtQueue! Either a
downstream element calls Pull, finds no buffer, and does a
wait_cond(new buffer) or an upstream element calls Push, finds no
room, and does a wait_cond(new room). Thus, GstPtQueue contains all
the cond_wait / signal code.
=> The managing container (thread, pipeline) "wakes" up any sleep
conditions of its "bottom half". (In the scenario described, it
wakes the blocked downstream element's call to Pull.) The GstPtQueue
cond_wait section determines that it woke up due to a pending state
change and does a cothread_switch(0) to return to the main loop,
which then executes the state transition.
Note that a managing container will have only one sleep condition
in its "bottom half."
2. Element "blocked" on getting I/O and cannot execute its change_state.
=> We will provide an I/O library for the elements to use that does
not actually block. (A retry-loop with timeout or select() on
2 -- or more -- file descriptors: one the one you want I/O from,
the other one that GStreamer uses to "wake" everyone up.) The
I/O library determines that it was woken due to a pending state
change and does a cothread_switch(0) to return to the main loop,
which then executes the state transition.
Note that a managing container will have only one elements in
the middle of doing blocking I/O.
3. Element using a library (code out of its control) which blocks for
some reason (e.g., using real blocking I/O) so main loop never gets
run to execute change_state.
=> Build in some timeout in the manging container (the "top half")
when waiting for bottom half to respond to pending state. If
managing container times out, kill the element's thread with a
signal (or series of signals -- escalating priority). This
requires that the element (the "bottom half") have matching
signal handler(s) that execute(s) the state-transition.
--------------------------------------------------------
- III. State-transition Approach and Responsibility -
--------------------------------------------------------
A. The "top half" context of the managing container. (This is likely the
context of the application.)
Call change_state on the managing container (GstPipeline, GstPtThread).
If its "bottom half" (main_loop) is asleep, signal the condition to
wake it up. Then do a cond_wait for the "bottom half" to execute the
state transition and return (once the state has been changed).
B. The main_loop (the "bottom half") of the managing container.
Needs to check for pending state transition after every switch back from
one of its elements. If a pending state is found, it calls change_state
on each of its elements, signals the "top half" that the state has been
changed, then continues executing the plan (if Playing) or puts itself
to sleep (Paused, Ready).
C. Element.
Implement a change_state function to make transition for that element.
The elements' change_state is what actually changes the state variable
and notifies the scheduler that the state was changed. This function
may also do things like close or open resources.
NOTE: when an element goes through certain state transitions (e.g., from
Paused to Ready) its state (stack) will be wiped out. If it wants to
preserve any state or data, it needs to store the information in a safe
place.
D. Cothread Scheduler.
Gets notified of state transition by elements' change_state functions
then (re)set the plan accordingly. Assuming
NULL <-> READY <-> PAUSED <-> PLAYING, some would be
+ Paused -> Playing: jump back where you were in the Plan and continue
its execution
+ Ready -> Paused: reset the cothread pointers foreach cothread in the
Plan (don't run)

View file

@ -8,4 +8,4 @@ endif
SUBDIRS = $(GNOME_SUBDS) \ SUBDIRS = $(GNOME_SUBDS) \
helloworld helloworld2 \ helloworld helloworld2 \
queue queue2 queue3 queue4 \ queue queue2 queue3 queue4 \
launch thread xml plugins typefind launch thread xml plugins typefind mixer

View file

@ -2,94 +2,36 @@
#include <gnome.h> #include <gnome.h>
static void static void
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data) autoplug_have_size (GstElement *element, guint width, guint height,
GtkWidget *socket)
{ {
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data); gtk_widget_set_usize(socket,width,height);
*(gboolean *)data = TRUE;
} }
gboolean static void
idle_func (gpointer data) gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
{ {
return gst_bin_iterate (GST_BIN (data)); GstElement *osssink, *videosink;
}
static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element)
{
gboolean found = FALSE;
GstElement *typefind;
GstCaps *caps = NULL;
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
GST_ELEMENT_NAME(element), &found);
typefind = gst_elementfactory_make ("typefind", "typefind");
g_return_val_if_fail (typefind != NULL, FALSE);
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
gst_pad_connect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_add (bin, typefind);
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
// push a buffer... the have_type signal handler will set the found flag
gst_bin_iterate (bin);
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
gst_pad_disconnect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_remove (bin, typefind);
gst_object_unref (GST_OBJECT (typefind));
return caps;
}
int main(int argc,char *argv[])
{
GstElement *disksrc, *osssink, *videosink;
GstElement *bin;
GtkWidget *appwindow; GtkWidget *appwindow;
GstCaps *srccaps;
GstElement *new_element; GstElement *new_element;
GstAutoplug *autoplug; GstAutoplug *autoplug;
GtkWidget *socket; GtkWidget *socket;
GstElement *autobin;
GstElement *disksrc;
GstElement *cache;
g_thread_init(NULL); GST_DEBUG (0,"GstPipeline: play have type\n");
gst_init(&argc,&argv);
gnome_init("autoplug","0.0.1", argc,argv);
if (argc != 2) { gst_element_set_state (pipeline, GST_STATE_PAUSED);
g_print("usage: %s <filename>\n", argv[0]);
exit(-1);
}
/* create a new bin to hold the elements */ disksrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source");
bin = gst_pipeline_new("pipeline"); autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
g_assert(bin != NULL); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
/* create a disk reader */ // disconnect the typefind from the pipeline and remove it
disksrc = gst_elementfactory_make("disksrc", "disk_source"); gst_element_disconnect (cache, "src", typefind, "sink");
g_assert(disksrc != NULL); gst_bin_remove (GST_BIN (autobin), typefind);
gtk_object_set(GTK_OBJECT(disksrc),"location", argv[1],NULL);
gst_bin_add (GST_BIN (bin), disksrc);
srccaps = gst_play_typefind (GST_BIN (bin), disksrc);
if (!srccaps) {
g_print ("could not autoplug, unknown media type...\n");
exit (-1);
}
/* and an audio sink */ /* and an audio sink */
osssink = gst_elementfactory_make("osssink", "play_audio"); osssink = gst_elementfactory_make("osssink", "play_audio");
g_assert(osssink != NULL); g_assert(osssink != NULL);
@ -102,7 +44,7 @@ int main(int argc,char *argv[])
g_assert (autoplug != NULL); g_assert (autoplug != NULL);
new_element = gst_autoplug_to_renderers (autoplug, new_element = gst_autoplug_to_renderers (autoplug,
srccaps, caps,
videosink, videosink,
osssink, osssink,
NULL); NULL);
@ -112,42 +54,122 @@ int main(int argc,char *argv[])
exit (-1); exit (-1);
} }
gst_bin_remove (GST_BIN (bin), disksrc); gst_element_set_name (new_element, "new_element");
// FIXME hack, reparent the disksrc so the scheduler doesn't break
bin = gst_pipeline_new("pipeline");
gst_bin_add (GST_BIN (bin), disksrc); gst_bin_add (GST_BIN (autobin), new_element);
gst_bin_add (GST_BIN (bin), new_element);
gst_element_connect (disksrc, "src", new_element, "sink"); gtk_object_set (GTK_OBJECT (cache), "reset", TRUE, NULL);
appwindow = gnome_app_new("autoplug demo","autoplug demo"); gst_element_connect (cache, "src", new_element, "sink");
appwindow = gnome_app_new ("autoplug demo","autoplug demo");
socket = gtk_socket_new (); socket = gtk_socket_new ();
gtk_widget_show (socket); gtk_widget_show (socket);
gnome_app_set_contents(GNOME_APP(appwindow), gnome_app_set_contents (GNOME_APP (appwindow),
GTK_WIDGET (socket)); GTK_WIDGET (socket));
gtk_widget_realize (socket); gtk_widget_realize (socket);
gtk_socket_steal (GTK_SOCKET (socket), gtk_socket_steal (GTK_SOCKET (socket),
gst_util_get_int_arg (GTK_OBJECT (videosink), "xid")); gst_util_get_int_arg (GTK_OBJECT (videosink), "xid"));
gtk_widget_set_usize(socket,320,240);
gtk_widget_show_all(appwindow); gtk_widget_show_all (appwindow);
xmlSaveFile("xmlTest.gst", gst_xml_write(GST_ELEMENT(bin))); gtk_signal_connect (GTK_OBJECT (videosink), "have_size",
GTK_SIGNAL_FUNC (autoplug_have_size), socket);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
xmlSaveFile("xmlTest.gst", gst_xml_write (GST_ELEMENT (pipeline)));
}
gboolean
idle_func (gpointer data)
{
return gst_bin_iterate (GST_BIN (data));
}
static void
gst_play_cache_empty (GstElement *element, GstElement *pipeline)
{
GstElement *autobin;
GstElement *disksrc;
GstElement *cache;
GstElement *new_element;
fprintf (stderr, "have cache empty\n");
gst_element_set_state (pipeline, GST_STATE_PAUSED);
disksrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source");
autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
gst_element_disconnect (disksrc, "src", cache, "sink");
gst_element_disconnect (cache, "src", new_element, "sink");
gst_bin_remove (GST_BIN (autobin), cache);
gst_element_connect (disksrc, "src", new_element, "sink");
gst_element_set_state (pipeline, GST_STATE_PLAYING);
fprintf (stderr, "done with cache_empty\n");
}
int main(int argc,char *argv[])
{
GstElement *disksrc;
GstElement *pipeline;
GstElement *autobin;
GstElement *typefind;
GstElement *cache;
g_thread_init(NULL);
gst_init(&argc,&argv);
gnome_init("autoplug","0.0.1", argc,argv);
if (argc != 2) {
g_print("usage: %s <filename>\n", argv[0]);
exit(-1);
}
/* create a new pipeline to hold the elements */
pipeline = gst_pipeline_new("pipeline");
g_assert(pipeline != NULL);
/* create a disk reader */
disksrc = gst_elementfactory_make("disksrc", "disk_source");
g_assert(disksrc != NULL);
gtk_object_set(GTK_OBJECT(disksrc),"location", argv[1],NULL);
gst_bin_add (GST_BIN (pipeline), disksrc);
autobin = gst_bin_new ("autobin");
cache = gst_elementfactory_make ("autoplugcache", "cache");
gtk_signal_connect (GTK_OBJECT (cache), "cache_empty", GTK_SIGNAL_FUNC (gst_play_cache_empty), pipeline);
typefind = gst_elementfactory_make ("typefind", "typefind");
gtk_signal_connect (GTK_OBJECT (typefind), "have_type", GTK_SIGNAL_FUNC (gst_play_have_type), pipeline);
gst_bin_add (GST_BIN (autobin), cache);
gst_bin_add (GST_BIN (autobin), typefind);
gst_element_connect (cache, "src", typefind, "sink");
gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink");
gst_bin_add (GST_BIN( pipeline), autobin);
gst_element_connect (disksrc, "src", autobin, "sink");
/* start playing */ /* start playing */
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_PLAYING); gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING);
gtk_idle_add(idle_func, bin); gtk_idle_add (idle_func, pipeline);
gst_main ();
gst_main(); /* stop the pipeline */
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
/* stop the bin */ gst_object_unref (GST_OBJECT (pipeline));
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_NULL);
gst_pipeline_destroy(bin);
exit(0); exit(0);
} }

View file

@ -4,10 +4,13 @@
* demonstrates the adder plugin and the volume envelope plugin * demonstrates the adder plugin and the volume envelope plugin
* work in progress but do try it out * work in progress but do try it out
* *
* Latest change : 16/04/2001 * Latest change : 28/04/2001
* multiple input channels allowed * trying to adapt to incsched
* volume envelope adapted * delayed start for channels > 1
* Version : 0.3 * now works by quickhacking the
* adder plugin to set
* GST_ELEMENT_COTHREAD_STOPPING
* Version : 0.5
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -15,8 +18,10 @@
#include "mixer.h" #include "mixer.h"
#include <unistd.h> #include <unistd.h>
//#define WITH_BUG
//#define WITH_BUG2
//#define DEBUG //#define DEBUG
//#define AUTOPLUG /* define if you want autoplugging of input channels */
/* function prototypes */ /* function prototypes */
input_channel_t* create_input_channel (int id, char* location); input_channel_t* create_input_channel (int id, char* location);
@ -35,55 +40,50 @@ void eos(GstElement *element)
// playing = FALSE; // playing = FALSE;
} }
static void
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
{
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
*(gboolean *)data = TRUE;
}
static GstCaps* static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element) gst_play_typefind (GstBin *bin, GstElement *element)
{ {
gboolean found = FALSE;
GstElement *typefind; GstElement *typefind;
GstElement *pipeline;
GstCaps *caps = NULL; GstCaps *caps = NULL;
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n", GST_DEBUG (0,"GstPipeline: typefind for element \"%s\"\n",
GST_ELEMENT_NAME(element), &found); GST_ELEMENT_NAME(element));
pipeline = gst_pipeline_new ("autoplug_pipeline");
typefind = gst_elementfactory_make ("typefind", "typefind"); typefind = gst_elementfactory_make ("typefind", "typefind");
g_return_val_if_fail (typefind != NULL, FALSE); g_return_val_if_fail (typefind != NULL, FALSE);
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
gst_pad_connect (gst_element_get_pad (element, "src"), gst_pad_connect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink")); gst_element_get_pad (typefind, "sink"));
gst_bin_add (bin, typefind); gst_bin_add (bin, typefind);
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (bin));
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING); gst_element_set_state (pipeline, GST_STATE_PLAYING);
// push a buffer... the have_type signal handler will set the found flag // push a buffer... the have_type signal handler will set the found flag
gst_bin_iterate (bin); gst_bin_iterate (GST_BIN (pipeline));
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL); gst_element_set_state (pipeline, GST_STATE_NULL);
caps = gst_pad_get_caps (gst_element_get_pad (element, "src")); caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
gst_pad_disconnect (gst_element_get_pad (element, "src"), gst_pad_disconnect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink")); gst_element_get_pad (typefind, "sink"));
gst_bin_remove (bin, typefind); gst_bin_remove (bin, typefind);
gst_bin_remove (GST_BIN (pipeline), GST_ELEMENT (bin));
gst_object_unref (GST_OBJECT (typefind)); gst_object_unref (GST_OBJECT (typefind));
gst_object_unref (GST_OBJECT (pipeline));
return caps; return caps;
} }
int main(int argc,char *argv[]) int main(int argc,char *argv[])
{ {
int i; int i, j;
int num_channels; int num_channels;
gboolean done;
char buffer[20]; char buffer[20];
@ -108,38 +108,41 @@ int main(int argc,char *argv[])
/* set up output channel and main bin */ /* set up output channel and main bin */
/* create adder */ /* create adder */
adder = gst_elementfactory_make("adder", "adderel"); adder = gst_elementfactory_make ("adder", "adderel");
/* create an audio sink */ /* create an audio sink */
audiosink = gst_elementfactory_make("esdsink", "play_audio"); audiosink = gst_elementfactory_make ("esdsink", "play_audio");
/* create main bin */ /* create main bin */
main_bin = gst_bin_new("bin"); main_bin = gst_pipeline_new("bin");
/* connect adder and output to bin */ /* connect adder and output to bin */
GST_INFO (0, "main: adding adder to bin");
gst_bin_add(GST_BIN(main_bin), adder); gst_bin_add (GST_BIN(main_bin), adder);
gst_bin_add(GST_BIN(main_bin), audiosink); GST_INFO (0, "main: adding audiosink to bin");
gst_bin_add (GST_BIN(main_bin), audiosink);
/* connect adder and audiosink */ /* connect adder and audiosink */
gst_pad_connect(gst_element_get_pad(adder,"src"), gst_pad_connect(gst_element_get_pad(adder,"src"),
gst_element_get_pad(audiosink,"sink")); gst_element_get_pad(audiosink,"sink"));
/* create input channels, add to bin and connect */ /* start looping */
input_channels = NULL; input_channels = NULL;
for (i = 1; i < argc; ++i) for (i = 1; i < argc; ++i)
{ {
printf ("Opening channel %d from file %s...\n", i, argv[i]); printf ("Opening channel %d from file %s...\n", i, argv[i]);
channel_in = create_input_channel (i, argv[i]); channel_in = create_input_channel (i, argv[i]);
input_channels = g_list_append (input_channels, channel_in); input_channels = g_list_append (input_channels, channel_in);
gst_bin_add(GST_BIN(main_bin), channel_in->pipe);
if (i > 1) gst_element_set_state (main_bin, GST_STATE_PAUSED);
gst_bin_add (GST_BIN(main_bin), channel_in->pipe);
/* request pads and connect to adder */ /* request pads and connect to adder */
GST_INFO (0, "requesting pad\n");
pad = gst_element_request_pad_by_name (adder, "sink%d"); pad = gst_element_request_pad_by_name (adder, "sink%d");
g_print ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad)); printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
sprintf (buffer, "channel%d", i); sprintf (buffer, "channel%d", i);
gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad); gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad);
@ -178,24 +181,32 @@ int main(int argc,char *argv[])
env_register_cp (channel_in->volenv, num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */ env_register_cp (channel_in->volenv, num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */
} }
env_register_cp (channel_in->volenv, num_channels * 10.0 , 1.0 / num_channels); /* to end level */ env_register_cp (channel_in->volenv, num_channels * 10.0 , 1.0 / num_channels); /* to end level */
xmlSaveFile("mixer.xml", gst_xml_write(GST_ELEMENT(main_bin)));
/* start playing */
gst_element_set_state(main_bin, GST_STATE_PLAYING);
// write out the schedule
gst_schedule_show(GST_ELEMENT_SCHED(main_bin));
playing = TRUE;
j = 0;
//printf ("main: start iterating from 0");
while (playing && j < 100)
{
// printf ("main: iterating %d\n", j);
gst_bin_iterate(GST_BIN(main_bin));
//fprintf(stderr,"after iterate()\n");
++j;
}
} }
printf ("main: all the channels are open\n");
/* sleep a few seconds doesn't seem to help anyway */ while (playing)
{
printf ("Sleeping a few seconds ...\n");
sleep (2);
printf ("Waking up ...\n");
/* start playing */
gst_element_set_state(main_bin, GST_STATE_PLAYING);
playing = TRUE;
while (playing) {
gst_bin_iterate(GST_BIN(main_bin)); gst_bin_iterate(GST_BIN(main_bin));
//fprintf(stderr,"after iterate()\n");
} }
/* stop the bin */ /* stop the bin */
gst_element_set_state(main_bin, GST_STATE_NULL); gst_element_set_state(main_bin, GST_STATE_NULL);
@ -228,11 +239,10 @@ create_input_channel (int id, char* location)
GstAutoplug *autoplug; GstAutoplug *autoplug;
GstCaps *srccaps; GstCaps *srccaps;
GstElement *new_element; GstElement *new_element;
GstElement *decoder;
#ifdef DEBUG GST_DEBUG (0, "c_i_p : creating channel with id %d for file %s\n",
printf ("DEBUG : c_i_p : creating channel with id %d for file %s\n",
id, location); id, location);
#endif
/* allocate channel */ /* allocate channel */
@ -245,23 +255,21 @@ create_input_channel (int id, char* location)
/* create channel */ /* create channel */
#ifdef DEBUG GST_DEBUG (0, "c_i_p : creating pipeline\n");
printf ("DEBUG : c_i_p : creating pipeline\n");
#endif
channel->pipe = gst_bin_new ("pipeline"); sprintf (buffer, "pipeline%d", id);
channel->pipe = gst_bin_new (buffer);
g_assert(channel->pipe != NULL); g_assert(channel->pipe != NULL);
/* create elements */ /* create elements */
#ifdef DEBUG GST_DEBUG(0, "c_i_p : creating disksrc\n");
printf ("DEBUG : c_i_p : creating disksrc\n");
#endif
sprintf (buffer, "disksrc%d", id); sprintf (buffer, "disksrc%d", id);
channel->disksrc = gst_elementfactory_make ("disksrc", buffer); channel->disksrc = gst_elementfactory_make ("disksrc", buffer);
g_assert(channel->disksrc != NULL); g_assert(channel->disksrc != NULL);
GST_DEBUG(0, "c_i_p : setting location\n");
gtk_object_set(GTK_OBJECT(channel->disksrc),"location", location, NULL); gtk_object_set(GTK_OBJECT(channel->disksrc),"location", location, NULL);
/* add disksrc to the bin before autoplug */ /* add disksrc to the bin before autoplug */
@ -286,8 +294,24 @@ create_input_channel (int id, char* location)
printf ("DEBUG : c_i_p : getting srccaps\n"); printf ("DEBUG : c_i_p : getting srccaps\n");
#endif #endif
#ifdef WITH_BUG
srccaps = gst_play_typefind (GST_BIN (channel->pipe), channel->disksrc); srccaps = gst_play_typefind (GST_BIN (channel->pipe), channel->disksrc);
#endif
#ifdef WITH_BUG2
{
GstElement *pipeline;
pipeline = gst_pipeline_new ("autoplug_pipeline");
gst_bin_add (GST_BIN (pipeline), channel->pipe);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_bin_remove (GST_BIN (pipeline), channel->pipe);
}
#endif
#ifdef AUTOPLUG
if (!srccaps) { if (!srccaps) {
g_print ("could not autoplug, unknown media type...\n"); g_print ("could not autoplug, unknown media type...\n");
exit (-1); exit (-1);
@ -311,7 +335,24 @@ create_input_channel (int id, char* location)
g_print ("could not autoplug, no suitable codecs found...\n"); g_print ("could not autoplug, no suitable codecs found...\n");
exit (-1); exit (-1);
} }
#else
new_element = gst_bin_new ("autoplug_bin");
/* static plug, use mad plugin and assume mp3 input */
decoder = gst_elementfactory_make ("mad", "mpg123");
gst_bin_add (GST_BIN (new_element), decoder);
gst_element_add_ghost_pad (new_element,
gst_element_get_pad (decoder, "sink"), "sink");
gst_element_add_ghost_pad (new_element,
gst_element_get_pad (decoder, "src"), "src_00");
#endif
xmlSaveFile ("mixer.gst", gst_xml_write (new_element));
gst_bin_add (GST_BIN(channel->pipe), channel->volenv); gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
gst_bin_add (GST_BIN (channel->pipe), new_element); gst_bin_add (GST_BIN (channel->pipe), new_element);

View file

@ -90,6 +90,7 @@ libgstincludedir = $(includedir)/gst
libgstinclude_HEADERS = \ libgstinclude_HEADERS = \
cothreads.h \ cothreads.h \
gst.h \ gst.h \
gsttypes.h \
gstautoplug.h \ gstautoplug.h \
gstbin.h \ gstbin.h \
gstbuffer.h \ gstbuffer.h \
@ -128,7 +129,7 @@ noinst_HEADERS = \
gstsparc.h \ gstsparc.h \
gstpropsprivate.h gstpropsprivate.h
CFLAGS = $(LIBGST_CFLAGS) CFLAGS = $(LIBGST_CFLAGS) -D_GNU_SOURCE
LIBS = $(LIBGST_LIBS) LIBS = $(LIBGST_LIBS)
libgst_la_LDFLAGS = -version-info $(GST_LIBVERSION) libgst_la_LDFLAGS = -version-info $(GST_LIBVERSION)

View file

@ -1,6 +1,7 @@
filterdir = $(libdir)/gst filterdir = $(libdir)/gst
filter_LTLIBRARIES = libgststaticautoplug.la libgststaticautoplugrender.la filter_LTLIBRARIES = libgststaticautoplug.la libgststaticautoplugrender.la \
libgstautoplugcache.la libgstautoplugger.la
libgststaticautoplug_la_SOURCES = \ libgststaticautoplug_la_SOURCES = \
gststaticautoplug.c gststaticautoplug.c
@ -8,5 +9,12 @@ libgststaticautoplug_la_SOURCES = \
libgststaticautoplugrender_la_SOURCES = \ libgststaticautoplugrender_la_SOURCES = \
gststaticautoplugrender.c gststaticautoplugrender.c
libgstautoplugcache_la_SOURCES = gstautoplugcache.c
libgstautoplugger_la_SOURCES = gstautoplugger.c
libgststaticautoplug_la_LDFLAGS = -version-info $(GST_LIBVERSION) libgststaticautoplug_la_LDFLAGS = -version-info $(GST_LIBVERSION)
libgststaticautoplugrender_la_LDFLAGS = -version-info $(GST_LIBVERSION) libgststaticautoplugrender_la_LDFLAGS = -version-info $(GST_LIBVERSION)
libgstautoplugcache_la_LDFLAGS = -version-info $(GST_LIBVERSION)
noinst_PROGRAMS = autoplugtest
autoplugtest_LDADD = $(GST_LIBS)

View file

@ -0,0 +1,92 @@
#include <gst/gst.h>
#include <string.h>
GstElement *pipeline, *src, *autobin, *cache, *typefind, *decoder, *sink;
void cache_empty(GstElement *element, gpointer private) {
fprintf(stderr,"have cache empty\n");
gst_element_set_state (pipeline, GST_STATE_PAUSED);
gst_element_disconnect(src,"src",cache,"sink");
gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
gst_element_disconnect(cache,"src",decoder,"sink");
gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
gst_bin_remove (GST_BIN(autobin), cache);
gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
gst_element_connect(src,"src",decoder,"sink");
gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
gst_element_set_state (pipeline, GST_STATE_PLAYING);
gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
fprintf(stderr,"done with cache_empty\n");
}
void have_type(GstElement *element, GstCaps *caps, GstCaps **private_caps) {
fprintf(stderr,"have caps, mime type is %s\n",gst_caps_get_mime(caps));
gst_element_set_state (pipeline, GST_STATE_PAUSED);
// disconnect the typefind from the pipeline and remove it
gst_element_disconnect(cache,"src",typefind,"sink");
gst_bin_remove(GST_BIN(autobin),typefind);
gst_schedule_show (GST_ELEMENT_SCHED(pipeline));
if (strstr(gst_caps_get_mime(caps),"mp3")) {
decoder = gst_elementfactory_make ("mad","decoder");
sink = gst_elementfactory_make ("osssink","sink");
gst_bin_add(GST_BIN(autobin),decoder);
gst_bin_add(GST_BIN(autobin),sink);
gst_element_connect(decoder,"src",sink,"sink");
gtk_object_set (GTK_OBJECT(cache), "reset", TRUE, NULL);
gst_element_connect(cache,"src",decoder,"sink");
}
else if (strstr(gst_caps_get_mime(caps),"x-ogg")) {
decoder = gst_elementfactory_make ("vorbisdec","decoder");
sink = gst_elementfactory_make ("osssink","sink");
gst_bin_add(GST_BIN(autobin),decoder);
gst_bin_add(GST_BIN(autobin),sink);
gst_element_connect(decoder,"src",sink,"sink");
gtk_object_set (GTK_OBJECT(cache), "reset", TRUE, NULL);
gst_element_connect(cache,"src",decoder,"sink");
}
gst_element_set_state (pipeline, GST_STATE_PLAYING);
fprintf(stderr,"done with have_type signal\n");
}
int main (int argc,char *argv[]) {
GstCaps *caps;
int i;
gst_init(&argc,&argv);
pipeline = gst_pipeline_new("pipeline");
src = gst_elementfactory_make ("disksrc","src");
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
gst_bin_add (GST_BIN(pipeline),src);
autobin = gst_bin_new("autobin");
cache = gst_elementfactory_make ("autoplugcache","cache");
gtk_signal_connect (GTK_OBJECT(cache),"cache_empty",GTK_SIGNAL_FUNC(cache_empty),NULL);
typefind = gst_elementfactory_make ("typefind", "typefind");
gtk_signal_connect (GTK_OBJECT(typefind),"have_type",GTK_SIGNAL_FUNC(have_type),&caps);
gst_bin_add (GST_BIN(autobin),cache);
gst_bin_add (GST_BIN(autobin),typefind);
gst_element_connect(cache,"src",typefind,"sink");
gst_element_add_ghost_pad(autobin,gst_element_get_pad(cache,"sink"),"sink");
gst_bin_add (GST_BIN(pipeline), autobin);
gst_element_connect (src,"src",autobin,"sink");
gst_element_set_state(pipeline,GST_STATE_PLAYING);
while (1)
gst_bin_iterate(GST_BIN(pipeline));
}

View file

@ -0,0 +1,371 @@
/* GStreamer
* Copyright (C) 2001 RidgeRun, Inc. (www.ridgerun.com)
*
* gstautoplugcache.c: Data cache for the dynamic autoplugger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/gst.h>
GstElementDetails gst_autoplugcache_details = {
"AutoplugCache",
"Connection",
"Data cache for the dynamic autoplugger",
VERSION,
"Erik Walthinsen <omega@temple-baptist.com>",
"(C) 2001 RidgeRun, Inc. (www.ridgerun.com)",
};
#define GST_TYPE_AUTOPLUGCACHE \
(gst_autoplugcache_get_type())
#define GST_AUTOPLUGCACHE(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_AUTOPLUGCACHE,GstAutoplugCache))
#define GST_AUTOPLUGCACHE_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_AUTOPLUGCACHE,GstAutoplugCacheClass))
#define GST_IS_AUTOPLUGCACHE(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_AUTOPLUGCACHE))
#define GST_IS_AUTOPLUGCACHE_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_AUTOPLUGCACHE))
typedef struct _GstAutoplugCache GstAutoplugCache;
typedef struct _GstAutoplugCacheClass GstAutoplugCacheClass;
struct _GstAutoplugCache {
GstElement element;
GstPad *sinkpad, *srcpad;
gboolean caps_proxy;
GList *cache;
GList *cache_start;
gint buffer_count;
GList *current_playout;
gboolean fire_empty;
gboolean fire_first;
};
struct _GstAutoplugCacheClass {
GstElementClass parent_class;
void (*first_buffer) (GstElement *element, GstBuffer *buf);
void (*cache_empty) (GstElement *element);
};
/* Cache signals and args */
enum {
FIRST_BUFFER,
CACHE_EMPTY,
LAST_SIGNAL
};
enum {
ARG_0,
ARG_BUFFER_COUNT,
ARG_CAPS_PROXY,
ARG_RESET
};
static void gst_autoplugcache_class_init (GstAutoplugCacheClass *klass);
static void gst_autoplugcache_init (GstAutoplugCache *cache);
static void gst_autoplugcache_set_arg (GtkObject *object, GtkArg *arg, guint id);
static void gst_autoplugcache_get_arg (GtkObject *object, GtkArg *arg, guint id);
static void gst_autoplugcache_loop (GstElement *element);
static GstPadNegotiateReturn gst_autoplugcache_nego_src (GstPad *pad, GstCaps **caps, gpointer *data);
static GstPadNegotiateReturn gst_autoplugcache_nego_sink (GstPad *pad, GstCaps **caps, gpointer *data);
static GstElementStateReturn gst_autoplugcache_change_state (GstElement *element);
static GstElementClass *parent_class = NULL;
static guint gst_autoplugcache_signals[LAST_SIGNAL] = { 0 };
GtkType
gst_autoplugcache_get_type(void) {
static GtkType autoplugcache_type = 0;
if (!autoplugcache_type) {
static const GtkTypeInfo autoplugcache_info = {
"GstAutoplugCache",
sizeof(GstAutoplugCache),
sizeof(GstAutoplugCacheClass),
(GtkClassInitFunc)gst_autoplugcache_class_init,
(GtkObjectInitFunc)gst_autoplugcache_init,
(GtkArgSetFunc)gst_autoplugcache_set_arg,
(GtkArgGetFunc)gst_autoplugcache_get_arg,
(GtkClassInitFunc)NULL,
};
autoplugcache_type = gtk_type_unique (GST_TYPE_ELEMENT, &autoplugcache_info);
}
return autoplugcache_type;
}
static void
gst_autoplugcache_class_init (GstAutoplugCacheClass *klass)
{
GtkObjectClass *gtkobject_class;
GstElementClass *gstelement_class;
gtkobject_class = (GtkObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
parent_class = gtk_type_class (GST_TYPE_ELEMENT);
gst_autoplugcache_signals[FIRST_BUFFER] =
gtk_signal_new ("first_buffer", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstAutoplugCacheClass, first_buffer),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GTK_TYPE_POINTER);
gst_autoplugcache_signals[CACHE_EMPTY] =
gtk_signal_new ("cache_empty", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstAutoplugCacheClass, cache_empty),
gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (gtkobject_class, gst_autoplugcache_signals, LAST_SIGNAL);
gtk_object_add_arg_type ("GstAutoplugCache::buffer_count", GTK_TYPE_INT,
GTK_ARG_READABLE, ARG_BUFFER_COUNT);
gtk_object_add_arg_type ("GstAutoplugCache::caps_proxy", GTK_TYPE_BOOL,
GTK_ARG_READWRITE, ARG_CAPS_PROXY);
gtk_object_add_arg_type ("GstAutoplugCache::reset", GTK_TYPE_BOOL,
GTK_ARG_WRITABLE, ARG_RESET);
gtkobject_class->set_arg = gst_autoplugcache_set_arg;
gtkobject_class->get_arg = gst_autoplugcache_get_arg;
gstelement_class->change_state = gst_autoplugcache_change_state;
}
static void
gst_autoplugcache_init (GstAutoplugCache *cache)
{
gst_element_set_loop_function(GST_ELEMENT(cache), GST_DEBUG_FUNCPTR(gst_autoplugcache_loop));
cache->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
// gst_pad_set_negotiate_function (cache->sinkpad, gst_autoplugcache_nego_sink);
gst_element_add_pad (GST_ELEMENT(cache), cache->sinkpad);
cache->srcpad = gst_pad_new ("src", GST_PAD_SRC);
// gst_pad_set_negotiate_function (cache->srcpad, gst_autoplugcache_nego_src);
gst_element_add_pad (GST_ELEMENT(cache), cache->srcpad);
cache->caps_proxy = FALSE;
// provide a zero basis for the cache
cache->cache = g_list_prepend(NULL, NULL);
cache->cache_start = cache->cache;
cache->buffer_count = 0;
cache->current_playout = 0;
cache->fire_empty = FALSE;
cache->fire_first = FALSE;
}
static void
gst_autoplugcache_loop (GstElement *element)
{
GstAutoplugCache *cache;
GstBuffer *buf = NULL;
cache = GST_AUTOPLUGCACHE (element);
/* Theory:
* The cache is a doubly-linked list. The front of the list is the most recent
* buffer, the end of the list is the first buffer. The playout pointer always
* points to the latest buffer sent out the end. cache points to the front
* (most reccent) of the list at all times. cache_start points to the first
* buffer, i.e. the end of the list.
* If the playout pointer does not have a prev (towards the most recent) buffer
* (== NULL), a buffer must be pulled from the sink pad and added to the cache.
* When the playout pointer gets reset (as in a set_arg), the cache is walked
* without problems, because the playout pointer has a non-NULL next. When
* the playout pointer hits the end of cache again it has to start pulling.
*/
do {
// the first time through, the current_playout pointer is going to be NULL
if (cache->current_playout == NULL) {
// get a buffer
buf = gst_pad_pull (cache->sinkpad);
// add it to the cache, though cache == NULL
gst_buffer_ref (buf);
cache->cache = g_list_prepend (cache->cache, buf);
cache->buffer_count++;
// set the current_playout pointer
cache->current_playout = cache->cache;
gtk_signal_emit (GTK_OBJECT(cache), gst_autoplugcache_signals[FIRST_BUFFER], buf);
// send the buffer on its way
gst_pad_push (cache->srcpad, buf);
}
// the steady state is where the playout is at the front of the cache
else if (g_list_previous(cache->current_playout) == NULL) {
// if we've been told to fire an empty signal (after a reset)
if (cache->fire_empty) {
int oldstate = GST_STATE(cache);
fprintf(stderr,"at front of cache, about to pull, but firing signal\n");
gst_object_ref (GST_OBJECT (cache));
gtk_signal_emit (GTK_OBJECT(cache), gst_autoplugcache_signals[CACHE_EMPTY], NULL);
if (GST_STATE(cache) != oldstate) {
gst_object_ref (GST_OBJECT (cache));
GST_DEBUG(GST_CAT_AUTOPLUG, "state changed during signal, aborting\n");
cothread_switch(cothread_current_main());
}
gst_object_unref (GST_OBJECT (cache));
}
// get a buffer
buf = gst_pad_pull (cache->sinkpad);
// add it to the front of the cache
gst_buffer_ref (buf);
cache->cache = g_list_prepend (cache->cache, buf);
cache->buffer_count++;
// set the current_playout pointer
cache->current_playout = cache->cache;
// send the buffer on its way
gst_pad_push (cache->srcpad, buf);
}
// otherwise we're trundling through existing cached buffers
else {
// move the current_playout pointer
cache->current_playout = g_list_previous (cache->current_playout);
if (cache->fire_first) {
gtk_signal_emit (GTK_OBJECT(cache), gst_autoplugcache_signals[FIRST_BUFFER], buf);
cache->fire_first = FALSE;
}
// push that buffer
gst_pad_push (cache->srcpad, GST_BUFFER(cache->current_playout->data));
}
} while (!GST_FLAG_IS_SET (element, GST_ELEMENT_COTHREAD_STOPPING));
}
static GstPadNegotiateReturn
gst_autoplugcache_nego_src (GstPad *pad, GstCaps **caps, gpointer *data)
{
GstAutoplugCache *cache = GST_AUTOPLUGCACHE (GST_PAD_PARENT (pad));
return gst_pad_negotiate_proxy (pad, cache->sinkpad, caps);
}
static GstPadNegotiateReturn
gst_autoplugcache_nego_sink (GstPad *pad, GstCaps **caps, gpointer *data)
{
GstAutoplugCache *cache = GST_AUTOPLUGCACHE (GST_PAD_PARENT (pad));
return gst_pad_negotiate_proxy (pad, cache->srcpad, caps);
}
static GstElementStateReturn
gst_autoplugcache_change_state (GstElement *element)
{
// FIXME this should do something like free the cache on ->NULL
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
}
static void
gst_autoplugcache_set_arg (GtkObject *object, GtkArg *arg, guint id)
{
GstAutoplugCache *cache;
cache = GST_AUTOPLUGCACHE (object);
switch (id) {
case ARG_CAPS_PROXY:
cache->caps_proxy = GTK_VALUE_BOOL(*arg);
GST_DEBUG(0,"caps_proxy is %d\n",cache->caps_proxy);
if (cache->caps_proxy) {
gst_pad_set_negotiate_function (cache->sinkpad, GST_DEBUG_FUNCPTR(gst_autoplugcache_nego_sink));
gst_pad_set_negotiate_function (cache->srcpad, GST_DEBUG_FUNCPTR(gst_autoplugcache_nego_src));
} else {
gst_pad_set_negotiate_function (cache->sinkpad, NULL);
gst_pad_set_negotiate_function (cache->srcpad, NULL);
}
break;
case ARG_RESET:
// no idea why anyone would set this to FALSE, but just in case ;-)
if (GTK_VALUE_BOOL(*arg)) {
fprintf(stderr,"resetting playout pointer\n");
// reset the playout pointer to the begining again
cache->current_playout = cache->cache_start;
// now we can fire a signal when the cache runs dry
cache->fire_empty = TRUE;
// also set it up to fire the first_buffer signal again
cache->fire_first = TRUE;
}
break;
default:
break;
}
}
static void
gst_autoplugcache_get_arg (GtkObject *object, GtkArg *arg, guint id)
{
GstAutoplugCache *cache;
cache = GST_AUTOPLUGCACHE (object);
switch (id) {
case ARG_BUFFER_COUNT:
GTK_VALUE_INT(*arg) = cache->buffer_count;
break;
case ARG_CAPS_PROXY:
GTK_VALUE_BOOL(*arg) = cache->caps_proxy;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
static gboolean
plugin_init (GModule *module, GstPlugin *plugin)
{
GstElementFactory *factory;
factory = gst_elementfactory_new ("autoplugcache", GST_TYPE_AUTOPLUGCACHE,
&gst_autoplugcache_details);
g_return_val_if_fail (factory != NULL, FALSE);
gst_plugin_add_factory (plugin, factory);
return TRUE;
}
GstPluginDesc plugin_desc = {
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"autoplugcache",
plugin_init
};

View file

@ -0,0 +1,606 @@
/* GStreamer
* Copyright (C) 2001 RidgeRun, Inc. (www.ridgerun.com)
*
* gstautoplugger.c: Data for the dynamic autopluggerger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gst/gst.h>
GstElementDetails gst_autoplugger_details = {
"Dynamic autoplugger",
"Autoplugger",
"Magic element that converts from any type to any other",
VERSION,
"Erik Walthinsen <omega@temple-baptist.com>",
"(C) 2001 RidgeRun, Inc. (www.ridgerun.com)",
};
#define GST_TYPE_AUTOPLUGGER \
(gst_autoplugger_get_type())
#define GST_AUTOPLUGGER(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_AUTOPLUGGER,GstAutoplugger))
#define GST_AUTOPLUGGER_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_AUTOPLUGGER,GstAutopluggerClass))
#define GST_IS_AUTOPLUGGER(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_AUTOPLUGGER))
#define GST_IS_AUTOPLUGGER_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_AUTOPLUGGER))
typedef struct _GstAutoplugger GstAutoplugger;
typedef struct _GstAutopluggerClass GstAutopluggerClass;
struct _GstAutoplugger {
GstBin bin;
gint paused;
GstElement *cache;
gboolean cache_first_buffer;
GstPad *cache_sinkpad, *cache_srcpad;
GstElement *typefind;
GstPad *typefind_sinkpad;
GstPad *sinkpadpeer, *srcpadpeer;
GstCaps *sinkcaps, *srccaps;
GstCaps *sinktemplatecaps;
GstAutoplug *autoplug;
GstElement *autobin;
gboolean disable_nocaps;
};
struct _GstAutopluggerClass {
GstBinClass parent_class;
};
/* signals and args */
enum {
LAST_SIGNAL
};
enum {
ARG_0,
};
static void gst_autoplugger_class_init (GstAutopluggerClass *klass);
static void gst_autoplugger_init (GstAutoplugger *queue);
static void gst_autoplugger_set_arg (GtkObject *object, GtkArg *arg, guint id);
static void gst_autoplugger_get_arg (GtkObject *object, GtkArg *arg, guint id);
//static GstElementStateReturn gst_autoplugger_change_state (GstElement *element);
static void gst_autoplugger_external_sink_caps_changed (GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger);
static void gst_autoplugger_external_src_caps_changed (GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger);
static void gst_autoplugger_external_sink_caps_nego_failed (GstPad *pad, gboolean *result, GstAutoplugger *autoplugger);
static void gst_autoplugger_external_src_caps_nego_failed (GstPad *pad, gboolean *result, GstAutoplugger *autoplugger);
static void gst_autoplugger_external_sink_connected (GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger);
static void gst_autoplugger_external_src_connected (GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger);
static void gst_autoplugger_cache_first_buffer (GstElement *element,GstBuffer *buf,GstAutoplugger *autoplugger);
static void gst_autoplugger_cache_empty (GstElement *element, GstAutoplugger *autoplugger);
static void gst_autoplugger_typefind_have_type (GstElement *element, GstCaps *caps, GstAutoplugger *autoplugger);
static GstElementClass *parent_class = NULL;
//static guint gst_autoplugger_signals[LAST_SIGNAL] = { 0 };
GtkType
gst_autoplugger_get_type(void) {
static GtkType autoplugger_type = 0;
if (!autoplugger_type) {
static const GtkTypeInfo autoplugger_info = {
"GstAutoplugger",
sizeof(GstAutoplugger),
sizeof(GstAutopluggerClass),
(GtkClassInitFunc)gst_autoplugger_class_init,
(GtkObjectInitFunc)gst_autoplugger_init,
(GtkArgSetFunc)gst_autoplugger_set_arg,
(GtkArgGetFunc)gst_autoplugger_get_arg,
(GtkClassInitFunc)NULL,
};
autoplugger_type = gtk_type_unique (GST_TYPE_BIN, &autoplugger_info);
}
return autoplugger_type;
}
static void
gst_autoplugger_class_init (GstAutopluggerClass *klass)
{
GtkObjectClass *gtkobject_class;
GstElementClass *gstelement_class;
gtkobject_class = (GtkObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
parent_class = gtk_type_class (GST_TYPE_ELEMENT);
/*
gst_autoplugger_signals[_EMPTY] =
gtk_signal_new ("_empty", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstAutopluggerClass, _empty),
gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (gtkobject_class, gst_autoplugger_signals, LAST_SIGNAL);
*/
/*
gtk_object_add_arg_type ("GstAutoplugger::buffer_count", GTK_TYPE_INT,
GTK_ARG_READABLE, ARG_BUFFER_COUNT);
gtk_object_add_arg_type ("GstAutoplugger::reset", GTK_TYPE_BOOL,
GTK_ARG_WRITABLE, ARG_RESET);
*/
gtkobject_class->set_arg = gst_autoplugger_set_arg;
gtkobject_class->get_arg = gst_autoplugger_get_arg;
// gstelement_class->change_state = gst_autoplugger_change_state;
}
static void
gst_autoplugger_init (GstAutoplugger *autoplugger)
{
// create the autoplugger cache, which is the fundamental unit of the autopluggerger
// FIXME we need to find a way to set element's name before _init
// FIXME ... so we can name the subelements uniquely
autoplugger->cache = gst_elementfactory_make("autoplugcache", "unnamed_autoplugcache");
g_return_if_fail (autoplugger->cache != NULL);
GST_DEBUG(GST_CAT_AUTOPLUG, "turning on caps nego proxying in cache\n");
gtk_object_set(GTK_OBJECT(autoplugger->cache),"caps_proxy",TRUE,NULL);
// attach signals to the cache
gtk_signal_connect (GTK_OBJECT (autoplugger->cache), "first_buffer",
GTK_SIGNAL_FUNC (gst_autoplugger_cache_first_buffer), autoplugger);
// add the cache to self
gst_bin_add (GST_BIN(autoplugger), autoplugger->cache);
// get the cache's pads so we can attach stuff to them
autoplugger->cache_sinkpad = gst_element_get_pad (autoplugger->cache, "sink");
autoplugger->cache_srcpad = gst_element_get_pad (autoplugger->cache, "src");
// attach handlers to the typefind pads
gtk_signal_connect (GTK_OBJECT (autoplugger->cache_sinkpad), "caps_changed",
GTK_SIGNAL_FUNC (gst_autoplugger_external_sink_caps_changed), autoplugger);
gtk_signal_connect (GTK_OBJECT (autoplugger->cache_srcpad), "caps_changed",
GTK_SIGNAL_FUNC (gst_autoplugger_external_src_caps_changed), autoplugger);
gtk_signal_connect (GTK_OBJECT (autoplugger->cache_sinkpad), "caps_nego_failed",
GTK_SIGNAL_FUNC (gst_autoplugger_external_sink_caps_nego_failed), autoplugger);
gtk_signal_connect (GTK_OBJECT (autoplugger->cache_srcpad), "caps_nego_failed",
GTK_SIGNAL_FUNC (gst_autoplugger_external_src_caps_nego_failed), autoplugger);
// gtk_signal_connect (GTK_OBJECT (autoplugger->cache_sinkpad), "connected",
// GTK_SIGNAL_FUNC (gst_autoplugger_external_sink_connected), autoplugger);
// gtk_signal_connect (GTK_OBJECT (autoplugger->cache_srcpad), "connected",
// GTK_SIGNAL_FUNC (gst_autoplugger_external_src_connected), autoplugger);
// ghost both of these pads to the outside world
gst_element_add_ghost_pad (GST_ELEMENT(autoplugger), autoplugger->cache_sinkpad, "sink");
gst_element_add_ghost_pad (GST_ELEMENT(autoplugger), autoplugger->cache_srcpad, "src");
}
static void
gst_autoplugger_external_sink_connected(GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger)
{
GstPadTemplate *peertemplate;
GstCaps *peercaps, *peertemplatecaps;
GST_INFO(GST_CAT_AUTOPLUG, "have cache:sink connected");
// autoplugger->sinkpadpeer = peerpad;
if (autoplugger->sinkpadpeer) {
peercaps = GST_PAD_CAPS(autoplugger->sinkpadpeer);
if (peercaps)
GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer: %s",
gst_caps_get_mime(peercaps));
peertemplate = GST_PAD_PADTEMPLATE(autoplugger->sinkpadpeer);
if (peertemplate) {
peertemplatecaps = GST_PADTEMPLATE_CAPS(peertemplate);
if (peertemplatecaps) {
GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer's padtemplate %s",
gst_caps_get_mime(peertemplatecaps));
}
}
}
}
static void
gst_autoplugger_external_src_connected(GstPad *pad, GstPad *peerpad, GstAutoplugger *autoplugger)
{
GstPadTemplate *peertemplate;
GstCaps *peercaps, *peertemplatecaps;
GST_INFO(GST_CAT_AUTOPLUG, "have cache:src connected");
// autoplugger->srcpadpeer = peerpad;
if (autoplugger->srcpadpeer) {
peercaps = GST_PAD_CAPS(autoplugger->srcpadpeer);
if (peercaps)
GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer: %s",
gst_caps_get_mime(peercaps));
peertemplate = GST_PAD_PADTEMPLATE(autoplugger->srcpadpeer);
if (peertemplate) {
peertemplatecaps = GST_PADTEMPLATE_CAPS(peertemplate);
if (peertemplatecaps) {
GST_INFO(GST_CAT_AUTOPLUG, "there are some caps on this pad's peer's padtemplate %s",
gst_caps_get_mime(peertemplatecaps));
autoplugger->sinktemplatecaps = peertemplatecaps;
// GST_DEBUG(GST_CAT_AUTOPLUG, "turning on caps nego proxying in cache\n");
// gtk_object_set(GTK_OBJECT(autoplugger->cache),"caps_proxy",TRUE,NULL);
}
}
}
}
static void
gst_autoplugger_external_sink_caps_changed(GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger)
{
GST_INFO(GST_CAT_AUTOPLUG, "have cache:sink caps of %s\n",gst_caps_get_mime(caps));
autoplugger->sinkcaps = caps;
}
static void
gst_autoplugger_external_src_caps_changed(GstPad *pad, GstCaps *caps, GstAutoplugger *autoplugger)
{
GST_INFO(GST_CAT_AUTOPLUG, "have cache:src caps of %s\n",gst_caps_get_mime(caps));
autoplugger->srccaps = caps;
}
static gboolean
gst_autoplugger_autoplug(GstAutoplugger *autoplugger,GstPad *srcpad,GstCaps *srccaps,GstCaps *sinkcaps)
{
GstPad *sinkpad;
sinkpad = GST_PAD(GST_PAD_PEER(srcpad));
GST_DEBUG(GST_CAT_AUTOPLUG,"disconnecting %s:%s and %s:%s to autoplug between them\n",
GST_DEBUG_PAD_NAME(srcpad),GST_DEBUG_PAD_NAME(sinkpad));
GST_DEBUG(GST_CAT_AUTOPLUG,"srcpadcaps are of type %s\n",gst_caps_get_mime(srccaps));
GST_DEBUG(GST_CAT_AUTOPLUG,"sinkpadcaps are of type %s\n",gst_caps_get_mime(sinkcaps));
// disconnect the pads
GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting the pads that will be joined by an autobin\n");
gst_pad_disconnect(srcpad,sinkpad);
if (!autoplugger->autoplug) {
autoplugger->autoplug = gst_autoplugfactory_make("static");
g_return_val_if_fail(autoplugger->autoplug != NULL, FALSE);
}
GST_DEBUG(GST_CAT_AUTOPLUG, "building autoplugged bin between caps\n");
autoplugger->autobin = gst_autoplug_to_caps(autoplugger->autoplug,
srccaps,sinkcaps,NULL);
g_return_val_if_fail(autoplugger->autobin != NULL, FALSE);
gst_bin_add(GST_BIN(autoplugger),autoplugger->autobin);
gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
// FIXME this is a hack
// GST_DEBUG(GST_CAT_AUTOPLUG, "copying failed caps to srcpad %s:%s to ensure renego\n",GST_DEBUG_PAD_NAME(autoplugger->cache_srcpad));
// gst_pad_set_caps(srcpad,srccaps);
if (GST_PAD_CAPS(srcpad) == NULL) GST_DEBUG(GST_CAT_AUTOPLUG,"no caps on cache:src!\n");
// attach the autoplugged bin
GST_DEBUG(GST_CAT_AUTOPLUG, "attaching the autoplugged bin between the two pads\n");
gst_pad_connect(srcpad,gst_element_get_pad(autoplugger->autobin,"sink"));
gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
gst_pad_connect(gst_element_get_pad(autoplugger->autobin,"src_00"),sinkpad);
gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
// FIXME try to force the renego
// GST_DEBUG(GST_CAT_AUTOPLUG, "trying to force everyone to nego\n");
// gst_pad_renegotiate(gst_element_get_pad(autoplugger->autobin,"sink"));
// gst_pad_renegotiate(sinkpad);
return TRUE;
}
static void
gst_autoplugger_external_sink_caps_nego_failed(GstPad *pad, gboolean *result, GstAutoplugger *autoplugger)
{
GstPad *srcpad_peer;
GstPadTemplate *srcpad_peer_template;
GstCaps *srcpad_peer_caps;
GstPad *sinkpad_peer;
GstCaps *sinkpad_peer_caps;
GST_INFO(GST_CAT_AUTOPLUG, "have caps nego failure on sinkpad %s:%s!!!",GST_DEBUG_PAD_NAME(pad));
autoplugger->paused++;
if (autoplugger->paused == 1)
// try to PAUSE the whole thing
gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
srcpad_peer = GST_PAD(GST_PAD_PEER(autoplugger->cache_srcpad));
g_return_if_fail(srcpad_peer != NULL);
srcpad_peer_template = GST_PAD_PADTEMPLATE(srcpad_peer);
g_return_if_fail(srcpad_peer_template != NULL);
srcpad_peer_caps = GST_PADTEMPLATE_CAPS(srcpad_peer_template);
g_return_if_fail(srcpad_peer_caps != NULL);
sinkpad_peer = GST_PAD(GST_PAD_PEER(pad));
g_return_if_fail(sinkpad_peer != NULL);
sinkpad_peer_caps = GST_PAD_CAPS(sinkpad_peer);
g_return_if_fail(sinkpad_peer_caps != NULL);
if (gst_autoplugger_autoplug(autoplugger,autoplugger->cache_srcpad,sinkpad_peer_caps,srcpad_peer_caps))
*result = TRUE;
// force renego
gst_pad_renegotiate(GST_PAD(GST_PAD_PEER(autoplugger->cache_sinkpad)));
autoplugger->paused--;
if (autoplugger->paused == 0)
// try to PLAY the whole thing
gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
GST_INFO(GST_CAT_AUTOPLUG, "done dealing with caps nego failure on sinkpad %s:%s",GST_DEBUG_PAD_NAME(pad));
}
static void
gst_autoplugger_external_src_caps_nego_failed(GstPad *pad, gboolean *result, GstAutoplugger *autoplugger)
{
GstCaps *srcpad_caps;
GstPad *srcpad_peer;
GstPadTemplate *srcpad_peer_template;
GstCaps *srcpad_peer_caps;
GST_INFO(GST_CAT_AUTOPLUG, "have caps nego failure on srcpad %s:%s!!!",GST_DEBUG_PAD_NAME(pad));
autoplugger->paused++;
if (autoplugger->paused == 1)
// try to PAUSE the whole thing
gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
srcpad_caps = GST_PAD_CAPS(autoplugger->cache_srcpad);
srcpad_peer = GST_PAD(GST_PAD_PEER(autoplugger->cache_srcpad));
g_return_if_fail(srcpad_peer != NULL);
srcpad_peer_template = GST_PAD_PADTEMPLATE(srcpad_peer);
g_return_if_fail(srcpad_peer_template != NULL);
srcpad_peer_caps = GST_PADTEMPLATE_CAPS(srcpad_peer_template);
g_return_if_fail(srcpad_peer_caps != NULL);
if (gst_autoplugger_autoplug(autoplugger,autoplugger->cache_srcpad,srcpad_caps,srcpad_peer_caps))
*result = TRUE;
autoplugger->paused--;
if (autoplugger->paused == 0)
// try to PLAY the whole thing
gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
autoplugger->disable_nocaps = TRUE;
GST_INFO(GST_CAT_AUTOPLUG, "done dealing with caps nego failure on srcpad %s:%s",GST_DEBUG_PAD_NAME(pad));
}
static void
gst_autoplugger_cache_empty(GstElement *element, GstAutoplugger *autoplugger)
{
GstPad *cache_sinkpad_peer,*cache_srcpad_peer;
GST_INFO(GST_CAT_AUTOPLUG, "autoplugger cache has hit empty, we can now remove it");
autoplugger->paused++;
if (autoplugger->paused == 1)
// try to PAUSE the whole thing
gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
// disconnect the cache from its peers
GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting autoplugcache from its peers\n");
cache_sinkpad_peer = GST_PAD (GST_PAD_PEER(autoplugger->cache_sinkpad));
cache_srcpad_peer = GST_PAD (GST_PAD_PEER(autoplugger->cache_srcpad));
gst_pad_disconnect(cache_sinkpad_peer,autoplugger->cache_sinkpad);
gst_pad_disconnect(autoplugger->cache_srcpad,cache_srcpad_peer);
// remove the cache from self
GST_DEBUG(GST_CAT_AUTOPLUG, "removing the cache from the autoplugger\n");
gst_bin_remove (GST_BIN(autoplugger), autoplugger->cache);
// connect the two pads
GST_DEBUG(GST_CAT_AUTOPLUG, "reconnecting the autoplugcache's former peers\n");
gst_pad_connect(cache_sinkpad_peer,cache_srcpad_peer);
autoplugger->paused--;
if (autoplugger->paused == 0)
// try to PLAY the whole thing
gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
xmlSaveFile("autoplugger.gst", gst_xml_write(GST_ELEMENT_SCHED(autoplugger)->parent));
GST_INFO(GST_CAT_AUTOPLUG, "autoplugger_cache_empty finished");
}
static void
gst_autoplugger_typefind_have_type(GstElement *element, GstCaps *caps, GstAutoplugger *autoplugger)
{
GST_INFO(GST_CAT_AUTOPLUG, "typefind claims to have a type: %s",gst_caps_get_mime(caps));
gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
autoplugger->paused++;
if (autoplugger->paused == 1)
// try to PAUSE the whole thing
gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
// first disconnect the typefind and shut it down
GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting typefind from the cache\n");
gst_pad_disconnect(autoplugger->cache_srcpad,autoplugger->typefind_sinkpad);
gst_bin_remove(GST_BIN(autoplugger),autoplugger->typefind);
// FIXME FIXME now we'd compare caps and see if we need to autoplug something in the middle, but for
// now we're going to just reconnect where we left off
// FIXME FIXME FIXME!!!: this should really be done in the caps failure!!!
/*
if (!autoplugger->autoplug) {
autoplugger->autoplug = gst_autoplugfactory_make("static");
}
autoplugger->autobin = gst_autoplug_to_caps(autoplugger->autoplug,
caps,autoplugger->sinktemplatecaps,NULL);
g_return_if_fail(autoplugger->autobin != NULL);
gst_bin_add(GST_BIN(autoplugger),autoplugger->autobin);
// // re-attach the srcpad's original peer to the cache
// GST_DEBUG(GST_CAT_AUTOPLUG, "reconnecting the cache to the downstream peer\n");
// gst_pad_connect(autoplugger->cache_srcpad,autoplugger->srcpadpeer);
// attach the autoplugged bin
GST_DEBUG(GST_CAT_AUTOPLUG, "attaching the autoplugged bin between cache and downstream peer\n");
gst_pad_connect(autoplugger->cache_srcpad,gst_element_get_pad(autoplugger->autobin,"sink"));
gst_pad_connect(gst_element_get_pad(autoplugger->autobin,"src_00"),autoplugger->srcpadpeer);
*/
// FIXME set the caps on the new connection
// GST_DEBUG(GST_CAT_AUTOPLUG,"forcing caps on the typefound pad\n");
// gst_pad_set_caps(autoplugger->cache_srcpad,caps);
// reattach the original outside srcpad
GST_DEBUG(GST_CAT_AUTOPLUG,"re-attaching downstream peer to autoplugcache\n");
gst_pad_connect(autoplugger->cache_srcpad,autoplugger->srcpadpeer);
// now reset the autoplugcache
GST_DEBUG(GST_CAT_AUTOPLUG, "resetting the cache to send first buffer(s) again\n");
gtk_object_set(GTK_OBJECT(autoplugger->cache),"reset",TRUE,NULL);
// attach the cache_empty handler
// FIXME this is the wrong place, it shouldn't be done until we get successful caps nego!
gtk_signal_connect(GTK_OBJECT(autoplugger->cache),"cache_empty",
GTK_SIGNAL_FUNC(gst_autoplugger_cache_empty),autoplugger);
autoplugger->paused--;
if (autoplugger->paused == 0)
// try to PLAY the whole thing
gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
GST_INFO(GST_CAT_AUTOPLUG, "typefind_have_type finished");
gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
}
static void
gst_autoplugger_cache_first_buffer(GstElement *element,GstBuffer *buf,GstAutoplugger *autoplugger)
{
GST_INFO(GST_CAT_AUTOPLUG, "have first buffer through cache");
autoplugger->cache_first_buffer = TRUE;
// if there are no established caps, worry
if (!autoplugger->sinkcaps) {
GST_INFO(GST_CAT_AUTOPLUG, "have no caps for the buffer, Danger Will Robinson!");
if (autoplugger->disable_nocaps) {
GST_DEBUG(GST_CAT_AUTOPLUG, "not dealing with lack of caps this time\n");
return;
}
gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
autoplugger->paused++;
if (autoplugger->paused == 1)
// try to PAUSE the whole thing
gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PAUSED);
// detach the srcpad
GST_DEBUG(GST_CAT_AUTOPLUG, "disconnecting cache from its downstream peer\n");
autoplugger->srcpadpeer = GST_PAD(GST_PAD_PEER(autoplugger->cache_srcpad));
gst_pad_disconnect(autoplugger->cache_srcpad,autoplugger->srcpadpeer);
// instantiate the typefind and set up the signal handlers
if (!autoplugger->typefind) {
GST_DEBUG(GST_CAT_AUTOPLUG, "creating typefind and setting signal handler\n");
autoplugger->typefind = gst_elementfactory_make("typefind","unnamed_typefind");
autoplugger->typefind_sinkpad = gst_element_get_pad(autoplugger->typefind,"sink");
gtk_signal_connect(GTK_OBJECT(autoplugger->typefind),"have_type",
GTK_SIGNAL_FUNC (gst_autoplugger_typefind_have_type), autoplugger);
}
// add it to self and attach it
GST_DEBUG(GST_CAT_AUTOPLUG, "adding typefind to self and connecting to cache\n");
gst_bin_add(GST_BIN(autoplugger),autoplugger->typefind);
gst_pad_connect(autoplugger->cache_srcpad,autoplugger->typefind_sinkpad);
// bring the typefind into playing state
GST_DEBUG(GST_CAT_AUTOPLUG, "setting typefind state to PLAYING\n");
gst_element_set_state(autoplugger->cache,GST_STATE_PLAYING);
autoplugger->paused--;
if (autoplugger->paused == 0)
// try to PLAY the whole thing
gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
GST_INFO(GST_CAT_AUTOPLUG,"here we go into nothingness, hoping the typefind will return us to safety");
gst_schedule_show(GST_ELEMENT_SCHED(autoplugger));
} else {
// // attach the cache_empty handler, since the cache simply isn't needed
// gtk_signal_connect(GTK_OBJECT(autoplugger->cache),"cache_empty",
// GTK_SIGNAL_FUNC(gst_autoplugger_cache_empty),autoplugger);
}
}
static void
gst_autoplugger_set_arg (GtkObject *object, GtkArg *arg, guint id)
{
GstAutoplugger *autoplugger;
autoplugger = GST_AUTOPLUGGER (object);
switch (id) {
default:
break;
}
}
static void
gst_autoplugger_get_arg (GtkObject *object, GtkArg *arg, guint id)
{
GstAutoplugger *autoplugger;
autoplugger = GST_AUTOPLUGGER (object);
switch (id) {
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
static gboolean
plugin_init (GModule *module, GstPlugin *plugin)
{
GstElementFactory *factory;
factory = gst_elementfactory_new ("autoplugger", GST_TYPE_AUTOPLUGGER,
&gst_autoplugger_details);
g_return_val_if_fail (factory != NULL, FALSE);
gst_plugin_add_factory (plugin, factory);
return TRUE;
}
GstPluginDesc plugin_desc = {
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"autoplugger",
plugin_init
};

View file

@ -124,7 +124,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
if (gst_caps_check_compatibility (gst_padtemplate_get_caps (srctemp), if (gst_caps_check_compatibility (gst_padtemplate_get_caps (srctemp),
gst_padtemplate_get_caps (desttemp))) { gst_padtemplate_get_caps (desttemp))) {
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
"factory \"%s\" can connect with factory \"%s\"", src->name, dest->name); "factory \"%s\" can connect with factory \"%s\"\n", src->name, dest->name);
return TRUE; return TRUE;
} }
} }
@ -134,7 +134,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
srctemps = g_list_next (srctemps); srctemps = g_list_next (srctemps);
} }
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
"factory \"%s\" cannot connect with factory \"%s\"", src->name, dest->name); "factory \"%s\" cannot connect with factory \"%s\"\n", src->name, dest->name);
return FALSE; return FALSE;
} }

View file

@ -123,7 +123,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
desttemp->direction == GST_PAD_SINK) { desttemp->direction == GST_PAD_SINK) {
if (gst_caps_check_compatibility (GST_PADTEMPLATE_CAPS (srctemp), GST_PADTEMPLATE_CAPS (desttemp))) { if (gst_caps_check_compatibility (GST_PADTEMPLATE_CAPS (srctemp), GST_PADTEMPLATE_CAPS (desttemp))) {
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
"factory \"%s\" can connect with factory \"%s\"", src->name, dest->name); "factory \"%s\" can connect with factory \"%s\"\n", src->name, dest->name);
return TRUE; return TRUE;
} }
} }
@ -133,7 +133,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
srctemps = g_list_next (srctemps); srctemps = g_list_next (srctemps);
} }
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT, GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
"factory \"%s\" cannot connect with factory \"%s\"", src->name, dest->name); "factory \"%s\" cannot connect with factory \"%s\"\n", src->name, dest->name);
return FALSE; return FALSE;
} }
@ -154,12 +154,21 @@ gst_autoplug_pads_autoplug_func (GstElement *src, GstPad *pad, GstElement *sink)
if (gst_pad_get_direction(sinkpad) == GST_PAD_SINK && if (gst_pad_get_direction(sinkpad) == GST_PAD_SINK &&
!GST_PAD_CONNECTED (pad) && !GST_PAD_CONNECTED(sinkpad)) !GST_PAD_CONNECTED (pad) && !GST_PAD_CONNECTED(sinkpad))
{ {
GstElementState state = GST_STATE (gst_element_get_parent (src));
if (state == GST_STATE_PLAYING)
gst_element_set_state (GST_ELEMENT (gst_element_get_parent (src)), GST_STATE_PAUSED);
if ((connected = gst_pad_connect (pad, sinkpad))) { if ((connected = gst_pad_connect (pad, sinkpad))) {
if (state == GST_STATE_PLAYING)
gst_element_set_state (GST_ELEMENT (gst_element_get_parent (src)), GST_STATE_PLAYING);
break; break;
} }
else { else {
GST_DEBUG (0,"pads incompatible %s, %s\n", GST_PAD_NAME (pad), GST_PAD_NAME (sinkpad)); GST_DEBUG (0,"pads incompatible %s, %s\n", GST_PAD_NAME (pad), GST_PAD_NAME (sinkpad));
} }
if (state == GST_STATE_PLAYING)
gst_element_set_state (GST_ELEMENT (gst_element_get_parent (src)), GST_STATE_PLAYING);
} }
sinkpads = g_list_next(sinkpads); sinkpads = g_list_next(sinkpads);
} }
@ -423,12 +432,13 @@ differ:
// create a new queue and add to the previous bin // create a new queue and add to the previous bin
queue = gst_elementfactory_make("queue", g_strconcat("queue_", GST_ELEMENT_NAME(element), NULL)); queue = gst_elementfactory_make("queue", g_strconcat("queue_", GST_ELEMENT_NAME(element), NULL));
GST_DEBUG (0,"adding element \"%s\"\n", GST_ELEMENT_NAME (element)); GST_DEBUG (0,"adding element \"%s\"\n", GST_ELEMENT_NAME (element));
gst_bin_add(GST_BIN(thebin), queue);
gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (queue));
// this will be the new bin for all following elements // this will be the new bin for all following elements
thebin = gst_elementfactory_make("thread", g_strconcat("thread_", GST_ELEMENT_NAME(element), NULL)); thebin = gst_elementfactory_make("thread", g_strconcat("thread_", GST_ELEMENT_NAME(element), NULL));
gst_bin_add(GST_BIN(thebin), queue);
gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (queue));
srcpad = gst_element_get_pad(queue, "src"); srcpad = gst_element_get_pad(queue, "src");
gst_autoplug_pads_autoplug(thesrcelement, queue); gst_autoplug_pads_autoplug(thesrcelement, queue);

View file

@ -67,6 +67,11 @@ cothread_init (void)
{ {
cothread_context *ctx = (cothread_context *)malloc(sizeof(cothread_context)); cothread_context *ctx = (cothread_context *)malloc(sizeof(cothread_context));
// we consider the initiating process to be cothread 0
ctx->nthreads = 1;
ctx->current = 0;
ctx->data = g_hash_table_new(g_str_hash, g_str_equal);
GST_INFO (GST_CAT_COTHREADS,"initializing cothreads"); GST_INFO (GST_CAT_COTHREADS,"initializing cothreads");
if (_cothread_key == -1) { if (_cothread_key == -1) {
@ -89,12 +94,14 @@ cothread_init (void)
ctx->threads[0]->sp = (void *)CURRENT_STACK_FRAME; ctx->threads[0]->sp = (void *)CURRENT_STACK_FRAME;
ctx->threads[0]->pc = 0; ctx->threads[0]->pc = 0;
GST_INFO (GST_CAT_COTHREADS,"0th thread is %p at sp:%p",ctx->threads[0], ctx->threads[0]->sp); // initialize the lock
#ifdef COTHREAD_ATOMIC
atomic_set (&ctx->threads[0]->lock, 0);
#else
ctx->threads[0]->lock = g_mutex_new();
#endif
// we consider the initiating process to be cothread 0 GST_INFO (GST_CAT_COTHREADS,"0th thread is %p at sp:%p",ctx->threads[0], ctx->threads[0]->sp);
ctx->nthreads = 1;
ctx->current = 0;
ctx->data = g_hash_table_new(g_str_hash, g_str_equal);
return ctx; return ctx;
} }
@ -118,7 +125,7 @@ cothread_create (cothread_context *ctx)
} }
GST_DEBUG (0,"pthread_self() %ld\n",pthread_self()); GST_DEBUG (0,"pthread_self() %ld\n",pthread_self());
//if (0) { //if (0) {
if (pthread_self() == 0) { if (pthread_self() == 0) { // FIXME uh, what does this test really do?
s = (cothread_state *)malloc(COTHREAD_STACKSIZE); s = (cothread_state *)malloc(COTHREAD_STACKSIZE);
GST_DEBUG (0,"new stack (case 1) at %p\n",s); GST_DEBUG (0,"new stack (case 1) at %p\n",s);
} else { } else {
@ -145,6 +152,13 @@ cothread_create (cothread_context *ctx)
// is this needed anymore? // is this needed anymore?
s->top_sp = s->sp; s->top_sp = s->sp;
// initialize the lock
#ifdef COTHREAD_ATOMIC
atomic_set (s->lock, 0);
#else
s->lock = g_mutex_new();
#endif
GST_INFO (GST_CAT_COTHREADS,"created cothread #%d: %p at sp:%p", ctx->nthreads, s, s->sp); GST_INFO (GST_CAT_COTHREADS,"created cothread #%d: %p at sp:%p", ctx->nthreads, s, s->sp);
ctx->threads[ctx->nthreads++] = s; ctx->threads[ctx->nthreads++] = s;
@ -186,6 +200,18 @@ cothread_main(cothread_context *ctx)
return ctx->threads[0]; return ctx->threads[0];
} }
/**
* cothread_current)main:
*
* Returns: the #cothread_state of the main (0th) thread in the current pthread
*/
cothread_state*
cothread_current_main(void)
{
cothread_context *ctx = pthread_getspecific(_cothread_key);
return ctx->threads[0];
}
static void static void
cothread_stub (void) cothread_stub (void)
{ {
@ -195,6 +221,11 @@ cothread_stub (void)
GST_DEBUG_ENTER(""); GST_DEBUG_ENTER("");
thread->flags |= COTHREAD_STARTED; thread->flags |= COTHREAD_STARTED;
//#ifdef COTHREAD_ATOMIC
// // do something here to lock
//#else
// g_mutex_lock(thread->lock);
//#endif
while (1) { while (1) {
thread->func(thread->argc,thread->argv); thread->func(thread->argc,thread->argv);
// we do this to avoid ever returning, we just switch to 0th thread // we do this to avoid ever returning, we just switch to 0th thread
@ -281,8 +312,22 @@ cothread_switch (cothread_state *thread)
#endif #endif
if (current == thread) goto selfswitch; if (current == thread) goto selfswitch;
// unlock the current thread, we're out of that context now
#ifdef COTHREAD_ATOMIC
// do something to unlock the cothread
#else
g_mutex_unlock(current->lock);
#endif
// lock the next cothread before we even switch to it
#ifdef COTHREAD_ATOMIC
// do something to lock the cothread
#else
g_mutex_lock(thread->lock);
#endif
// find the number of the thread to switch to // find the number of the thread to switch to
GST_INFO (GST_CAT_COTHREAD_SWITCH,"switching from cothread %d to to cothread #%d", GST_INFO (GST_CAT_COTHREAD_SWITCH,"switching from cothread #%d to cothread #%d",
ctx->current,thread->threadnum); ctx->current,thread->threadnum);
ctx->current = thread->threadnum; ctx->current = thread->threadnum;
@ -319,7 +364,7 @@ cothread_switch (cothread_state *thread)
#ifdef COTHREAD_PARANOID #ifdef COTHREAD_PARANOID
nothread: nothread:
g_print("cothread: there's no thread, strange...\n"); g_print("cothread: can't switch to NULL cothread!\n");
return; return;
nocontext: nocontext:
g_print("cothread: there's no context, help!\n"); g_print("cothread: there's no context, help!\n");
@ -332,3 +377,35 @@ selfswitch:
g_print("cothread: trying to switch to same thread, legal but not necessary\n"); g_print("cothread: trying to switch to same thread, legal but not necessary\n");
return; return;
} }
void
cothread_lock (cothread_state *thread)
{
#ifdef COTHREAD_ATOMIC
// do something to lock the cothread
#else
g_mutex_lock(thread->lock);
#endif
}
gboolean
cothread_trylock (cothread_state *thread)
{
#ifdef COTHREAD_ATOMIC
// do something to try to lock the cothread
#else
return g_mutex_trylock(thread->lock);
#endif
}
void
cothread_unlock (cothread_state *thread)
{
#ifdef COTHREAD_ATOMIC
// do something to unlock the cothread
#else
g_mutex_unlock(thread->lock);
#endif
}

View file

@ -26,6 +26,12 @@
#include <glib.h> #include <glib.h>
#include <setjmp.h> #include <setjmp.h>
#ifdef HAVE_ATOMIC_H
#include <asm/atomic.h>
#endif
#undef COTHREAD_ATOMIC
#ifndef CURRENT_STACK_FRAME #ifndef CURRENT_STACK_FRAME
#define CURRENT_STACK_FRAME ({ char __csf; &__csf; }) #define CURRENT_STACK_FRAME ({ char __csf; &__csf; })
#endif /* CURRENT_STACK_FRAME */ #endif /* CURRENT_STACK_FRAME */
@ -47,10 +53,16 @@ struct _cothread_state {
int flags; int flags;
void *sp; void *sp;
jmp_buf jmp;
/* is this needed any more? */ /* is this needed any more? */
void *top_sp; void *top_sp;
void *pc; void *pc;
jmp_buf jmp;
#ifdef COTHREAD_ATOMIC
atomic_t lock;
#else
GMutex *lock;
#endif
}; };
@ -63,6 +75,11 @@ void cothread_switch (cothread_state *thread);
void cothread_set_data (cothread_state *thread, gchar *key, gpointer data); void cothread_set_data (cothread_state *thread, gchar *key, gpointer data);
gpointer cothread_get_data (cothread_state *thread, gchar *key); gpointer cothread_get_data (cothread_state *thread, gchar *key);
void cothread_lock (cothread_state *thread);
gboolean cothread_trylock (cothread_state *thread);
void cothread_unlock (cothread_state *thread);
cothread_state* cothread_main (cothread_context *ctx); cothread_state* cothread_main (cothread_context *ctx);
cothread_state* cothread_current_main (void);
#endif /* __COTHREAD_H__ */ #endif /* __COTHREAD_H__ */

View file

@ -49,6 +49,7 @@ enum {
ARG_OUTPUT, ARG_OUTPUT,
ARG_PATTERN, ARG_PATTERN,
ARG_NUM_BUFFERS, ARG_NUM_BUFFERS,
ARG_EOS,
ARG_SILENT ARG_SILENT
}; };
@ -125,6 +126,8 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
GTK_ARG_READWRITE, ARG_PATTERN); GTK_ARG_READWRITE, ARG_PATTERN);
gtk_object_add_arg_type ("GstFakeSrc::num_buffers", GTK_TYPE_INT, gtk_object_add_arg_type ("GstFakeSrc::num_buffers", GTK_TYPE_INT,
GTK_ARG_READWRITE, ARG_NUM_BUFFERS); GTK_ARG_READWRITE, ARG_NUM_BUFFERS);
gtk_object_add_arg_type ("GstFakeSrc::eos", GTK_TYPE_BOOL,
GTK_ARG_READWRITE, ARG_EOS);
gtk_object_add_arg_type ("GstFakeSrc::silent", GTK_TYPE_BOOL, gtk_object_add_arg_type ("GstFakeSrc::silent", GTK_TYPE_BOOL,
GTK_ARG_READWRITE, ARG_SILENT); GTK_ARG_READWRITE, ARG_SILENT);
@ -222,6 +225,10 @@ gst_fakesrc_set_arg (GtkObject *object, GtkArg *arg, guint id)
case ARG_NUM_BUFFERS: case ARG_NUM_BUFFERS:
src->num_buffers = GTK_VALUE_INT (*arg); src->num_buffers = GTK_VALUE_INT (*arg);
break; break;
case ARG_EOS:
src->eos = GTK_VALUE_BOOL (*arg);
GST_INFO (0, "will EOS on next buffer");
break;
case ARG_SILENT: case ARG_SILENT:
src->silent = GTK_VALUE_BOOL (*arg); src->silent = GTK_VALUE_BOOL (*arg);
break; break;
@ -256,6 +263,8 @@ gst_fakesrc_get_arg (GtkObject *object, GtkArg *arg, guint id)
case ARG_NUM_BUFFERS: case ARG_NUM_BUFFERS:
GTK_VALUE_INT (*arg) = src->num_buffers; GTK_VALUE_INT (*arg) = src->num_buffers;
break; break;
case ARG_EOS:
GTK_VALUE_BOOL (*arg) = src->eos;
case ARG_SILENT: case ARG_SILENT:
GTK_VALUE_BOOL (*arg) = src->silent; GTK_VALUE_BOOL (*arg) = src->silent;
break; break;
@ -295,6 +304,12 @@ gst_fakesrc_get(GstPad *pad)
src->num_buffers--; src->num_buffers--;
} }
if (src->eos) {
GST_INFO (0, "fakesrc is setting eos on pad");
gst_pad_set_eos (pad);
return NULL;
}
if (!src->silent) if (!src->silent)
g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad)); g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad));
buf = gst_buffer_new(); buf = gst_buffer_new();
@ -336,7 +351,13 @@ gst_fakesrc_loop(GstElement *element)
} }
else { else {
if (src->num_buffers > 0) if (src->num_buffers > 0)
src->num_buffers--; src->num_buffers--;
}
if (src->eos) {
GST_INFO (0, "fakesrc is setting eos on pad");
gst_pad_set_eos (pad);
return;
} }
buf = gst_buffer_new(); buf = gst_buffer_new();

View file

@ -65,6 +65,7 @@ struct _GstFakeSrc {
GstElement element; GstElement element;
gboolean loop_based; gboolean loop_based;
gboolean eos;
gint numsrcpads; gint numsrcpads;
GSList *srcpads; GSList *srcpads;
GstFakeSrcOutputType output; GstFakeSrcOutputType output;

View file

@ -407,4 +407,4 @@ gst_sinesrc_factory_init (GstElementFactory *factory)
gst_elementfactory_add_padtemplate (factory, src_temp); gst_elementfactory_add_padtemplate (factory, src_temp);
return TRUE; return TRUE;
} }

View file

@ -174,21 +174,6 @@ gst_init_check (int *argc,
(*argv)[i] = NULL; (*argv)[i] = NULL;
} }
else if (!strncmp ("--gst-mask=", (*argv)[i], 11)) {
guint32 val;
// handle either 0xHEX or dec
if (*((*argv)[i]+12) == 'x') {
sscanf ((*argv)[i]+13, "%08x", &val);
} else {
sscanf ((*argv)[i]+11, "%d", &val);
}
gst_debug_set_categories (val);
gst_info_set_categories (val);
(*argv)[i] = NULL;
}
else if (!strncmp ("--gst-plugin-spew", (*argv)[i], 17)) { else if (!strncmp ("--gst-plugin-spew", (*argv)[i], 17)) {
_gst_plugin_spew = TRUE; _gst_plugin_spew = TRUE;
@ -247,10 +232,19 @@ gst_init_check (int *argc,
g_print ("--------------------------------------------------------\n"); g_print ("--------------------------------------------------------\n");
for (i = 0; i<GST_CAT_MAX_CATEGORY; i++) { for (i = 0; i<GST_CAT_MAX_CATEGORY; i++) {
g_print (" 0x%08x %s%s %s\n", 1<<i, if (gst_get_category_name(i)) {
(gst_info_get_categories() & (1<<i)?"(enabled)":" "), #if GST_DEBUG_COLOR
(gst_debug_get_categories() & (1<<i)?"/(enabled)":"/ "), g_print (" 0x%08x %s%s \033[%sm%s\033[00m\n", 1<<i,
gst_get_category_name (i)); (gst_info_get_categories() & (1<<i)?"(enabled)":" "),
(gst_debug_get_categories() & (1<<i)?"/(enabled)":"/ "),
_gst_category_colors[i], gst_get_category_name (i));
#else
g_print (" 0x%08x %s%s %s\n", 1<<i,
(gst_info_get_categories() & (1<<i)?"(enabled)":" "),
(gst_debug_get_categories() & (1<<i)?"/(enabled)":"/ "),
gst_get_category_name (i));
#endif
}
} }
ret = FALSE; ret = FALSE;

View file

@ -27,6 +27,7 @@
#include <glib.h> #include <glib.h>
#include <gst/gstversion.h> #include <gst/gstversion.h>
#include <gst/gsttypes.h>
#include <gst/gstinfo.h> #include <gst/gstinfo.h>
#include <gst/gstobject.h> #include <gst/gstobject.h>
@ -48,6 +49,7 @@
#include <gst/gsttrace.h> #include <gst/gsttrace.h>
#include <gst/gstxml.h> #include <gst/gstxml.h>
#include <gst/cothreads.h> #include <gst/cothreads.h>
#include <gst/gstscheduler.h>
#include <gst/gstparse.h> #include <gst/gstparse.h>

View file

@ -46,7 +46,6 @@ static gboolean gst_bin_change_state_type (GstBin *bin,
GstElementState state, GstElementState state,
GtkType type); GtkType type);
static void gst_bin_create_plan_func (GstBin *bin);
static gboolean gst_bin_iterate_func (GstBin *bin); static gboolean gst_bin_iterate_func (GstBin *bin);
static xmlNodePtr gst_bin_save_thyself (GstObject *object, xmlNodePtr parent); static xmlNodePtr gst_bin_save_thyself (GstObject *object, xmlNodePtr parent);
@ -113,8 +112,6 @@ gst_bin_class_init (GstBinClass *klass)
gtk_object_class_add_signals (gtkobject_class, gst_bin_signals, LAST_SIGNAL); gtk_object_class_add_signals (gtkobject_class, gst_bin_signals, LAST_SIGNAL);
klass->change_state_type = gst_bin_change_state_type; klass->change_state_type = gst_bin_change_state_type;
klass->create_plan = gst_bin_create_plan_func;
klass->schedule = gst_bin_schedule_func;
klass->iterate = gst_bin_iterate_func; klass->iterate = gst_bin_iterate_func;
gstobject_class->save_thyself = gst_bin_save_thyself; gstobject_class->save_thyself = gst_bin_save_thyself;
@ -155,6 +152,105 @@ gst_bin_new (const gchar *name)
return gst_elementfactory_make ("bin", name); return gst_elementfactory_make ("bin", name);
} }
static inline void
gst_bin_reset_element_sched (GstElement *element, GstSchedule *sched)
{
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "resetting element's scheduler");
// first remove the element from its current schedule, if any
// if (GST_ELEMENT_SCHED(element))
// GST_SCHEDULE_REMOVE_ELEMENT (GST_ELEMENT_SCHED(element), element);
// then set the new manager
gst_element_set_sched (element,sched);
// and add it to the new scheduler
// if (sched)
// GST_SCHEDULE_ADD_ELEMENT (sched, element);
}
void
gst_bin_set_element_sched (GstElement *element,GstSchedule *sched)
{
GList *children;
GstElement *child;
g_return_if_fail (element != NULL);
g_return_if_fail (GST_IS_ELEMENT(element));
g_return_if_fail (sched != NULL);
g_return_if_fail (GST_IS_SCHEDULE(sched));
GST_INFO (GST_CAT_SCHEDULING, "setting element \"%s\" sched to %p",GST_ELEMENT_NAME(element),
sched);
// if it's actually a Bin
if (GST_IS_BIN(element)) {
if (GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not resetting");
return;
}
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting children's schedule to parent's");
GST_SCHEDULE_ADD_ELEMENT (sched, element);
// set the children's schedule
children = GST_BIN(element)->children;
while (children) {
child = GST_ELEMENT (children->data);
children = g_list_next(children);
gst_bin_set_element_sched (child, sched);
}
// otherwise, if it's just a regular old element
} else {
GST_SCHEDULE_ADD_ELEMENT (sched, element);
}
}
void
gst_bin_unset_element_sched (GstElement *element)
{
GList *children;
GstElement *child;
g_return_if_fail (element != NULL);
g_return_if_fail (GST_IS_ELEMENT(element));
GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from it sched %p",
GST_ELEMENT_NAME(element),GST_ELEMENT_SCHED(element));
// if it's actually a Bin
if (GST_IS_BIN(element)) {
if (GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not unsetting sched");
return;
}
// FIXME this check should be irrelevant
if (GST_ELEMENT_SCHED (element))
GST_SCHEDULE_REMOVE_ELEMENT (GST_ELEMENT_SCHED(element), element);
// for each child, remove them from their schedule
children = GST_BIN(element)->children;
while (children) {
child = GST_ELEMENT (children->data);
children = g_list_next(children);
gst_bin_unset_element_sched (child);
}
// otherwise, if it's just a regular old element
} else {
// FIXME this check should be irrelevant
if (GST_ELEMENT_SCHED (element))
GST_SCHEDULE_REMOVE_ELEMENT (GST_ELEMENT_SCHED(element), element);
}
}
/** /**
* gst_bin_add: * gst_bin_add:
* @bin: #GstBin to add element to * @bin: #GstBin to add element to
@ -172,19 +268,30 @@ gst_bin_add (GstBin *bin,
g_return_if_fail (element != NULL); g_return_if_fail (element != NULL);
g_return_if_fail (GST_IS_ELEMENT (element)); g_return_if_fail (GST_IS_ELEMENT (element));
// must be NULL or PAUSED state in order to modify bin GST_DEBUG (GST_CAT_PARENTAGE, "adding element \"%s\" to bin \"%s\"\n",
g_return_if_fail ((GST_STATE (bin) == GST_STATE_NULL) || GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(bin));
(GST_STATE (bin) == GST_STATE_PAUSED));
// must be not be in PLAYING state in order to modify bin
// g_return_if_fail (GST_STATE (bin) != GST_STATE_PLAYING);
// the element must not already have a parent
g_return_if_fail (GST_ELEMENT_PARENT(element) == NULL);
// then check to see if the element's name is already taken in the bin
g_return_if_fail (gst_object_check_uniqueness (bin->children, GST_ELEMENT_NAME(element)) == TRUE);
// set the element's parent and add the element to the bin's list of children
gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
bin->children = g_list_append (bin->children, element); bin->children = g_list_append (bin->children, element);
bin->numchildren++; bin->numchildren++;
gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child %s", GST_ELEMENT_NAME (element)); ///// now we have to deal with manager stuff
// we can only do this if there's a scheduler:
// if we're not a manager, and aren't attached to anything, we have no sched (yet)
if (GST_ELEMENT_SCHED(bin) != NULL)
gst_bin_set_element_sched (element, GST_ELEMENT_SCHED(bin));
/* we know we have at least one child, we just added one... */ GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child \"%s\"", GST_ELEMENT_NAME (element));
// if (GST_STATE(element) < GST_STATE_READY)
// gst_bin_change_state_norecurse(bin,GST_STATE_READY);
gtk_signal_emit (GTK_OBJECT (bin), gst_bin_signals[OBJECT_ADDED], element); gtk_signal_emit (GTK_OBJECT (bin), gst_bin_signals[OBJECT_ADDED], element);
} }
@ -206,24 +313,32 @@ gst_bin_remove (GstBin *bin,
g_return_if_fail (GST_IS_ELEMENT (element)); g_return_if_fail (GST_IS_ELEMENT (element));
g_return_if_fail (bin->children != NULL); g_return_if_fail (bin->children != NULL);
// must be NULL or PAUSED state in order to modify bin // must not be in PLAYING state in order to modify bin
g_return_if_fail ((GST_STATE (bin) == GST_STATE_NULL) || g_return_if_fail (GST_STATE (bin) != GST_STATE_PLAYING);
(GST_STATE (bin) == GST_STATE_PAUSED));
// the element must have its parent set to the current bin
g_return_if_fail (GST_ELEMENT_PARENT(element) == (GstObject *)bin);
// the element must be in the bin's list of children
if (g_list_find(bin->children, element) == NULL) { if (g_list_find(bin->children, element) == NULL) {
// FIXME this should be a warning!!! // FIXME this should be a warning!!!
GST_ERROR_OBJECT(bin,element,"no such element in bin"); GST_ERROR_OBJECT(bin,element,"no such element in bin");
return; return;
} }
gst_object_unparent (GST_OBJECT (element)); // remove this element from the list of managed elements
gst_bin_unset_element_sched (element);
// now remove the element from the list of elements
bin->children = g_list_remove (bin->children, element); bin->children = g_list_remove (bin->children, element);
bin->numchildren--; bin->numchildren--;
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "removed child %s", GST_ELEMENT_NAME (element)); GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "removed child %s", GST_ELEMENT_NAME (element));
gst_object_unparent (GST_OBJECT (element));
/* if we're down to zero children, force state to NULL */ /* if we're down to zero children, force state to NULL */
if (bin->numchildren == 0) if (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL)
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL); gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
} }
@ -236,62 +351,47 @@ gst_bin_change_state (GstElement *element)
GstElement *child; GstElement *child;
GstElementStateReturn ret; GstElementStateReturn ret;
GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (element)); // GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (element));
g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE); g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
bin = GST_BIN (element); bin = GST_BIN (element);
// GST_DEBUG (0,"currently %d(%s), %d(%s) pending\n",GST_STATE (element), // GST_DEBUG (GST_CAT_STATES,"currently %d(%s), %d(%s) pending\n",GST_STATE (element),
// _gst_print_statename (GST_STATE (element)), GST_STATE_PENDING (element), // gst_element_statename (GST_STATE (element)), GST_STATE_PENDING (element),
// _gst_print_statename (GST_STATE_PENDING (element))); // gst_element_statename (GST_STATE_PENDING (element)));
GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing bin's state from %s to %s", GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing childrens' state from %s to %s",
_gst_print_statename (GST_STATE (element)), gst_element_statename (GST_STATE (element)),
_gst_print_statename (GST_STATE_PENDING (element))); gst_element_statename (GST_STATE_PENDING (element)));
// g_return_val_if_fail(bin->numchildren != 0, GST_STATE_FAILURE); // g_return_val_if_fail(bin->numchildren != 0, GST_STATE_FAILURE);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
{
GstObject *parent;
parent = gst_object_get_parent (GST_OBJECT (element));
if (!parent || !GST_IS_BIN (parent))
gst_bin_create_plan (bin);
else
GST_DEBUG (0,"not creating plan for '%s'\n",GST_ELEMENT_NAME (bin));
break;
}
case GST_STATE_READY_TO_NULL:
GST_FLAG_UNSET (bin, GST_BIN_FLAG_MANAGER);
default:
break;
}
// g_print("-->\n"); // g_print("-->\n");
children = bin->children; children = bin->children;
while (children) { while (children) {
child = GST_ELEMENT (children->data); child = GST_ELEMENT (children->data);
GST_DEBUG (0,"setting state on '%s'\n",GST_ELEMENT_NAME (child)); // GST_DEBUG (GST_CAT_STATES,"setting state on '%s'\n",GST_ELEMENT_NAME (child));
switch (gst_element_set_state (child, GST_STATE_PENDING (element))) { switch (gst_element_set_state (child, GST_STATE_PENDING (element))) {
case GST_STATE_FAILURE: case GST_STATE_FAILURE:
GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING; GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING;
GST_DEBUG (0,"child '%s' failed to go to state %d(%s)\n", GST_ELEMENT_NAME (child), GST_DEBUG (GST_CAT_STATES,"child '%s' failed to go to state %d(%s)\n", GST_ELEMENT_NAME (child),
GST_STATE_PENDING (element), _gst_print_statename (GST_STATE_PENDING (element))); GST_STATE_PENDING (element), gst_element_statename (GST_STATE_PENDING (element)));
return GST_STATE_FAILURE; return GST_STATE_FAILURE;
break; break;
case GST_STATE_ASYNC: case GST_STATE_ASYNC:
GST_DEBUG (0,"child '%s' is changing state asynchronously\n", GST_ELEMENT_NAME (child)); GST_DEBUG (GST_CAT_STATES,"child '%s' is changing state asynchronously\n", GST_ELEMENT_NAME (child));
break; break;
} }
// g_print("\n"); // g_print("\n");
children = g_list_next (children); children = g_list_next (children);
} }
// g_print("<-- \"%s\"\n",gst_object_get_name(GST_OBJECT(bin))); // g_print("<-- \"%s\"\n",GST_OBJECT_NAME(bin));
GST_INFO_ELEMENT (GST_CAT_STATES, element, "done changing bin's state from %s to %s",
gst_element_statename (GST_STATE (element)),
gst_element_statename (GST_STATE_PENDING (element)));
ret = gst_bin_change_state_norecurse (bin); ret = gst_bin_change_state_norecurse (bin);
return ret; return ret;
@ -301,10 +401,10 @@ gst_bin_change_state (GstElement *element)
static GstElementStateReturn static GstElementStateReturn
gst_bin_change_state_norecurse (GstBin *bin) gst_bin_change_state_norecurse (GstBin *bin)
{ {
if (GST_ELEMENT_CLASS (parent_class)->change_state) {
if (GST_ELEMENT_CLASS (parent_class)->change_state) GST_DEBUG_ELEMENT (GST_CAT_STATES, bin, "setting bin's own state\n");
return GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (bin)); return GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (bin));
else } else
return GST_STATE_FAILURE; return GST_STATE_FAILURE;
} }
@ -317,7 +417,7 @@ gst_bin_change_state_type(GstBin *bin,
GstElement *child; GstElement *child;
// g_print("gst_bin_change_state_type(\"%s\",%d,%d);\n", // g_print("gst_bin_change_state_type(\"%s\",%d,%d);\n",
// gst_object_get_name(GST_OBJECT(bin)),state,type); // GST_OBJECT_NAME(bin))),state,type);
g_return_val_if_fail (GST_IS_BIN (bin), FALSE); g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
g_return_val_if_fail (bin->numchildren != 0, FALSE); g_return_val_if_fail (bin->numchildren != 0, FALSE);
@ -359,7 +459,7 @@ gst_bin_set_state_type (GstBin *bin,
{ {
GstBinClass *oclass; GstBinClass *oclass;
GST_DEBUG (0,"gst_bin_set_state_type(\"%s\",%d,%d)\n", GST_DEBUG (GST_CAT_STATES,"gst_bin_set_state_type(\"%s\",%d,%d)\n",
GST_ELEMENT_NAME (bin), state,type); GST_ELEMENT_NAME (bin), state,type);
g_return_val_if_fail (bin != NULL, FALSE); g_return_val_if_fail (bin != NULL, FALSE);
@ -376,19 +476,30 @@ static void
gst_bin_real_destroy (GtkObject *object) gst_bin_real_destroy (GtkObject *object)
{ {
GstBin *bin = GST_BIN (object); GstBin *bin = GST_BIN (object);
GList *children; GList *children, *orig;
GstElement *child; GstElement *child;
GST_DEBUG (0,"in gst_bin_real_destroy()\n"); GST_DEBUG (GST_CAT_REFCOUNTING,"destroy()\n");
children = bin->children; if (bin->children) {
while (children) { orig = children = g_list_copy (bin->children);
child = GST_ELEMENT (children->data); while (children) {
gst_element_destroy (child); child = GST_ELEMENT (children->data);
children = g_list_next (children); //gst_object_unref (GST_OBJECT (child));
//gst_object_unparent (GST_OBJECT (child));
gst_bin_remove (bin, child);
children = g_list_next (children);
}
g_list_free (orig);
g_list_free (bin->children);
} }
bin->children = NULL;
bin->numchildren = 0;
g_list_free (bin->children); g_cond_free (bin->eoscond);
if (GTK_OBJECT_CLASS (parent_class)->destroy)
GTK_OBJECT_CLASS (parent_class)->destroy (object);
} }
/** /**
@ -416,7 +527,7 @@ gst_bin_get_by_name (GstBin *bin,
children = bin->children; children = bin->children;
while (children) { while (children) {
child = GST_ELEMENT (children->data); child = GST_ELEMENT (children->data);
if (!strcmp (gst_object_get_name (GST_OBJECT (child)),name)) if (!strcmp (GST_OBJECT_NAME(child),name))
return child; return child;
if (GST_IS_BIN (child)) { if (GST_IS_BIN (child)) {
GstElement *res = gst_bin_get_by_name (GST_BIN (child), name); GstElement *res = gst_bin_get_by_name (GST_BIN (child), name);
@ -521,7 +632,7 @@ gst_bin_restore_thyself (GstObject *object,
childlist = field->xmlChildrenNode; childlist = field->xmlChildrenNode;
while (childlist) { while (childlist) {
if (!strcmp (childlist->name, "element")) { if (!strcmp (childlist->name, "element")) {
GstElement *element = gst_element_load_thyself (childlist, GST_OBJECT (bin)); GstElement *element = gst_element_restore_thyself (childlist, GST_OBJECT (bin));
gst_bin_add (bin, element); gst_bin_add (bin, element);
} }
@ -569,23 +680,6 @@ gst_bin_iterate (GstBin *bin)
return eos; return eos;
} }
/**
* gst_bin_create_plan:
* @bin: #GstBin to create the plan for
*
* Let the bin figure out how to handle its children.
*/
void
gst_bin_create_plan (GstBin *bin)
{
GstBinClass *oclass;
oclass = GST_BIN_CLASS (GTK_OBJECT (bin)->klass);
if (oclass->create_plan)
(oclass->create_plan) (bin);
}
/* out internal element fired EOS, we decrement the number of pending EOS childs */ /* out internal element fired EOS, we decrement the number of pending EOS childs */
static void static void
gst_bin_received_eos (GstElement *element, GstBin *bin) gst_bin_received_eos (GstElement *element, GstBin *bin)
@ -601,290 +695,22 @@ gst_bin_received_eos (GstElement *element, GstBin *bin)
GST_UNLOCK (bin); GST_UNLOCK (bin);
} }
/**
* gst_bin_schedule:
* @bin: #GstBin to schedule
*
* Let the bin figure out how to handle its children.
*/
void
gst_bin_schedule (GstBin *bin)
{
GstBinClass *oclass;
oclass = GST_BIN_CLASS (GTK_OBJECT (bin)->klass);
if (oclass->schedule)
(oclass->schedule) (bin);
}
typedef struct { typedef struct {
gulong offset; gulong offset;
gulong size; gulong size;
} region_struct; } region_struct;
static void
gst_bin_create_plan_func (GstBin *bin)
{
GstElement *manager;
GList *elements;
GstElement *element;
#ifdef GST_DEBUG_ENABLED
const gchar *elementname;
#endif
GSList *pending = NULL;
GstBin *pending_bin;
GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (bin));
GST_INFO_ELEMENT (GST_CAT_PLANNING, bin, "creating plan");
// first figure out which element is the manager of this and all child elements
// if we're a managing bin ourselves, that'd be us
if (GST_FLAG_IS_SET (bin, GST_BIN_FLAG_MANAGER)) {
manager = GST_ELEMENT (bin);
GST_DEBUG (0,"setting manager to self\n");
// otherwise, it's what our parent says it is
} else {
manager = gst_element_get_manager (GST_ELEMENT (bin));
if (!manager) {
GST_DEBUG (0,"manager not set for element \"%s\" assuming manager is self\n", GST_ELEMENT_NAME (bin));
manager = GST_ELEMENT (bin);
GST_FLAG_SET (bin, GST_BIN_FLAG_MANAGER);
}
GST_DEBUG (0,"setting manager to \"%s\"\n", GST_ELEMENT_NAME (manager));
}
gst_element_set_manager (GST_ELEMENT (bin), manager);
// perform the first recursive pass of plan generation
// we set the manager of every element but those who manage themselves
// the need for cothreads is also determined recursively
GST_DEBUG (0,"performing first-phase recursion\n");
bin->need_cothreads = bin->use_cothreads;
if (bin->need_cothreads)
GST_DEBUG (0,"requiring cothreads because we're forced to\n");
elements = bin->children;
while (elements) {
element = GST_ELEMENT (elements->data);
elements = g_list_next (elements);
#ifdef GST_DEBUG_ENABLED
elementname = GST_ELEMENT_NAME (element);
#endif
GST_DEBUG (0,"have element \"%s\"\n",elementname);
// first set their manager
GST_DEBUG (0,"setting manager of \"%s\" to \"%s\"\n",elementname,GST_ELEMENT_NAME (manager));
gst_element_set_manager (element, manager);
// we do recursion and such for Bins
if (GST_IS_BIN (element)) {
// recurse into the child Bin
GST_DEBUG (0,"recursing into child Bin \"%s\" with manager \"%s\"\n",elementname,
GST_ELEMENT_NAME (element->manager));
gst_bin_create_plan (GST_BIN (element));
GST_DEBUG (0,"after recurse got manager \"%s\"\n",
GST_ELEMENT_NAME (element->manager));
// check to see if it needs cothreads and isn't self-managing
if (((GST_BIN (element))->need_cothreads) && !GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
GST_DEBUG (0,"requiring cothreads because child bin \"%s\" does\n",elementname);
bin->need_cothreads = TRUE;
}
} else {
// then we need to determine whether they need cothreads
// if it's a loop-based element, use cothreads
if (element->loopfunc != NULL) {
GST_DEBUG (0,"requiring cothreads because \"%s\" is a loop-based element\n",elementname);
GST_FLAG_SET (element, GST_ELEMENT_USE_COTHREAD);
// if it's a 'complex' element, use cothreads
} else if (GST_FLAG_IS_SET (element, GST_ELEMENT_COMPLEX)) {
GST_DEBUG (0,"requiring cothreads because \"%s\" is complex\n",elementname);
GST_FLAG_SET (element, GST_ELEMENT_USE_COTHREAD);
// if the element has more than one sink pad, use cothreads
} else if (element->numsinkpads > 1) {
GST_DEBUG (0,"requiring cothreads because \"%s\" has more than one sink pad\n",elementname);
GST_FLAG_SET (element, GST_ELEMENT_USE_COTHREAD);
}
if (GST_FLAG_IS_SET (element, GST_ELEMENT_USE_COTHREAD))
bin->need_cothreads = TRUE;
}
}
// if we're not a manager thread, we're done.
if (!GST_FLAG_IS_SET (bin, GST_BIN_FLAG_MANAGER)) {
GST_DEBUG_LEAVE("(\"%s\")",GST_ELEMENT_NAME (bin));
return;
}
// clear previous plan state
g_list_free (bin->managed_elements);
bin->managed_elements = NULL;
bin->num_managed_elements = 0;
// find all the managed children
// here we pull off the trick of walking an entire arbitrary tree without recursion
GST_DEBUG (0,"attempting to find all the elements to manage\n");
pending = g_slist_prepend (pending, bin);
do {
// retrieve the top of the stack and pop it
pending_bin = GST_BIN (pending->data);
pending = g_slist_remove (pending, pending_bin);
// walk the list of elements, find bins, and do stuff
GST_DEBUG (0,"checking Bin \"%s\" for managed elements\n",
GST_ELEMENT_NAME (pending_bin));
elements = pending_bin->children;
while (elements) {
element = GST_ELEMENT (elements->data);
elements = g_list_next (elements);
#ifdef GST_DEBUG_ENABLED
elementname = GST_ELEMENT_NAME (element);
#endif
// if it's ours, add it to the list
if (element->manager == GST_ELEMENT(bin)) {
// if it's a Bin, add it to the list of Bins to check
if (GST_IS_BIN (element)) {
GST_DEBUG (0,"flattened recurse into \"%s\"\n",elementname);
pending = g_slist_prepend (pending, element);
// otherwise add it to the list of elements
} else {
GST_DEBUG (0,"found element \"%s\" that I manage\n",elementname);
bin->managed_elements = g_list_prepend (bin->managed_elements, element);
bin->num_managed_elements++;
}
}
// else it's not ours and we need to wait for EOS notifications
else {
GST_DEBUG (0,"setting up EOS signal from \"%s\" to \"%s\"\n", elementname,
gst_element_get_name (GST_ELEMENT(bin)->manager));
gtk_signal_connect (GTK_OBJECT (element), "eos", gst_bin_received_eos, GST_ELEMENT(bin)->manager);
bin->eos_providers = g_list_prepend (bin->eos_providers, element);
bin->num_eos_providers++;
}
}
} while (pending);
GST_DEBUG (0,"have %d elements to manage, implementing plan\n",bin->num_managed_elements);
gst_bin_schedule(bin);
// g_print ("gstbin \"%s\", eos providers:%d\n",
// GST_ELEMENT_NAME (bin),
// bin->num_eos_providers);
GST_DEBUG_LEAVE("(\"%s\")",GST_ELEMENT_NAME (bin));
}
static gboolean static gboolean
gst_bin_iterate_func (GstBin *bin) gst_bin_iterate_func (GstBin *bin)
{ {
GList *chains; // only iterate if this is the manager bin
_GstBinChain *chain; if (GST_ELEMENT_SCHED(bin)->parent == GST_ELEMENT (bin)) {
GList *entries; return GST_SCHEDULE_ITERATE(GST_ELEMENT_SCHED(bin));
GstElement *entry; } else {
GList *pads; GST_DEBUG (GST_CAT_SCHEDULING, "this bin can't be iterated on!\n");
GstPad *pad;
GstBuffer *buf = NULL;
gint num_scheduled = 0;
gboolean eos = FALSE;
GST_DEBUG_ENTER("(\"%s\")", GST_ELEMENT_NAME (bin));
g_return_val_if_fail (bin != NULL, TRUE);
g_return_val_if_fail (GST_IS_BIN (bin), TRUE);
g_return_val_if_fail (GST_STATE (bin) == GST_STATE_PLAYING, TRUE);
// step through all the chains
chains = bin->chains;
while (chains) {
chain = (_GstBinChain *)(chains->data);
chains = g_list_next (chains);
if (!chain->need_scheduling) continue;
if (chain->need_cothreads) {
GList *entries;
// all we really have to do is switch to the first child
// FIXME this should be lots more intelligent about where to start
GST_DEBUG (0,"starting iteration via cothreads\n");
entries = chain->elements;
entry = NULL;
// find an element with a threadstate to start with
while (entries) {
entry = GST_ELEMENT (entries->data);
if (entry->threadstate)
break;
entries = g_list_next (entries);
}
// if we couldn't find one, bail out
if (entries == NULL)
GST_ERROR(GST_ELEMENT(bin),"no cothreaded elements found!");
GST_FLAG_SET (entry, GST_ELEMENT_COTHREAD_STOPPING);
GST_DEBUG (0,"set COTHREAD_STOPPING flag on \"%s\"(@%p)\n",
GST_ELEMENT_NAME (entry),entry);
cothread_switch (entry->threadstate);
} else {
GST_DEBUG (0,"starting iteration via chain-functions\n");
entries = chain->entries;
g_assert (entries != NULL);
while (entries) {
entry = GST_ELEMENT (entries->data);
entries = g_list_next (entries);
GST_DEBUG (0,"have entry \"%s\"\n",GST_ELEMENT_NAME (entry));
if (GST_IS_BIN (entry)) {
gst_bin_iterate (GST_BIN (entry));
} else {
pads = entry->pads;
while (pads) {
pad = GST_PAD (pads->data);
if (GST_RPAD_DIRECTION(pad) == GST_PAD_SRC) {
GST_DEBUG (0,"calling getfunc of %s:%s\n",GST_DEBUG_PAD_NAME(pad));
if (GST_REAL_PAD(pad)->getfunc == NULL)
fprintf(stderr, "error, no getfunc in \"%s\"\n", GST_ELEMENT_NAME (entry));
else
buf = (GST_REAL_PAD(pad)->getfunc)(pad);
if (buf) gst_pad_push(pad,buf);
}
pads = g_list_next (pads);
}
}
}
}
num_scheduled++;
} }
// check if nothing was scheduled that was ours.. return FALSE;
if (!num_scheduled) {
// are there any other elements that are still busy?
if (bin->num_eos_providers) {
GST_LOCK (bin);
GST_DEBUG (0,"waiting for eos providers\n");
g_cond_wait (bin->eoscond, GST_GET_LOCK(bin));
GST_DEBUG (0,"num eos providers %d\n", bin->num_eos_providers);
GST_UNLOCK (bin);
}
else {
gst_element_signal_eos (GST_ELEMENT (bin));
eos = TRUE;
}
}
GST_DEBUG_LEAVE("(%s)", GST_ELEMENT_NAME (bin));
return !eos;
} }

View file

@ -47,6 +47,8 @@ extern GstElementDetails gst_bin_details;
typedef enum { typedef enum {
/* this bin is a manager of child elements, i.e. a pipeline or thread */ /* this bin is a manager of child elements, i.e. a pipeline or thread */
GST_BIN_FLAG_MANAGER = GST_ELEMENT_FLAG_LAST, GST_BIN_FLAG_MANAGER = GST_ELEMENT_FLAG_LAST,
/* this bin is actually a meta-bin, and may need to be scheduled */
GST_BIN_SELF_SCHEDULABLE,
/* we prefer to have cothreads when its an option, over chain-based */ /* we prefer to have cothreads when its an option, over chain-based */
GST_BIN_FLAG_PREFER_COTHREADS, GST_BIN_FLAG_PREFER_COTHREADS,
@ -55,8 +57,8 @@ typedef enum {
GST_BIN_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 4, GST_BIN_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 4,
} GstBinFlags; } GstBinFlags;
typedef struct _GstBin GstBin; //typedef struct _GstBin GstBin;
typedef struct _GstBinClass GstBinClass; //typedef struct _GstBinClass GstBinClass;
typedef struct __GstBinChain _GstBinChain; typedef struct __GstBinChain _GstBinChain;
struct _GstBin { struct _GstBin {
@ -94,9 +96,6 @@ struct _GstBinClass {
gboolean (*change_state_type) (GstBin *bin, gboolean (*change_state_type) (GstBin *bin,
GstElementState state, GstElementState state,
GtkType type); GtkType type);
/* create a plan for the execution of the bin */
void (*create_plan) (GstBin *bin);
void (*schedule) (GstBin *bin);
/* run a full iteration of operation */ /* run a full iteration of operation */
gboolean (*iterate) (GstBin *bin); gboolean (*iterate) (GstBin *bin);
}; };
@ -116,6 +115,10 @@ GtkType gst_bin_get_type (void);
GstElement* gst_bin_new (const gchar *name); GstElement* gst_bin_new (const gchar *name);
#define gst_bin_destroy(bin) gst_object_destroy(GST_OBJECT(bin)) #define gst_bin_destroy(bin) gst_object_destroy(GST_OBJECT(bin))
void gst_bin_set_element_manager (GstElement *element, GstElement *manager);
void gst_bin_add_managed_element (GstBin *bin, GstElement *element);
void gst_bin_remove_managed_element (GstBin *bin, GstElement *element);
/* add and remove elements from the bin */ /* add and remove elements from the bin */
void gst_bin_add (GstBin *bin, void gst_bin_add (GstBin *bin,
GstElement *element); GstElement *element);
@ -129,8 +132,6 @@ GstElement* gst_bin_get_by_name_recurse_up (GstBin *bin,
const gchar *name); const gchar *name);
GList* gst_bin_get_list (GstBin *bin); GList* gst_bin_get_list (GstBin *bin);
void gst_bin_create_plan (GstBin *bin);
void gst_bin_schedule (GstBin *bin);
gboolean gst_bin_set_state_type (GstBin *bin, gboolean gst_bin_set_state_type (GstBin *bin,
GstElementState state, GstElementState state,
GtkType type); GtkType type);

View file

@ -448,7 +448,7 @@ gst_buffer_copy (GstBuffer *buffer)
// copy the absolute size // copy the absolute size
newbuf->size = buffer->size; newbuf->size = buffer->size;
// allocate space for the copy // allocate space for the copy
newbuf->data = (guchar *)g_malloc (buffer->data); newbuf->data = (guchar *)g_malloc (buffer->size);
// copy the data straight across // copy the data straight across
memcpy(newbuf,buffer->data,buffer->size); memcpy(newbuf,buffer->data,buffer->size);
// the new maxsize is the same as the size, since we just malloc'd it // the new maxsize is the same as the size, since we just malloc'd it

View file

@ -476,7 +476,7 @@ static gboolean
gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps) gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
{ {
if (fromcaps->id != tocaps->id) { if (fromcaps->id != tocaps->id) {
GST_DEBUG (0,"gstcaps: mime types differ (%s to %s)\n", GST_DEBUG (GST_CAT_CAPS,"mime types differ (%s to %s)\n",
gst_type_find_by_id (fromcaps->id)->mime, gst_type_find_by_id (fromcaps->id)->mime,
gst_type_find_by_id (tocaps->id)->mime); gst_type_find_by_id (tocaps->id)->mime);
return FALSE; return FALSE;
@ -487,13 +487,13 @@ gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
return gst_props_check_compatibility (fromcaps->properties, tocaps->properties); return gst_props_check_compatibility (fromcaps->properties, tocaps->properties);
} }
else { else {
GST_DEBUG (0,"gstcaps: no source caps\n"); GST_DEBUG (GST_CAT_CAPS,"no source caps\n");
return FALSE; return FALSE;
} }
} }
else { else {
// assume it accepts everything // assume it accepts everything
GST_DEBUG (0,"gstcaps: no caps\n"); GST_DEBUG (GST_CAT_CAPS,"no caps\n");
return TRUE; return TRUE;
} }
} }
@ -512,17 +512,17 @@ gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps)
{ {
if (fromcaps == NULL) { if (fromcaps == NULL) {
if (tocaps == NULL) { if (tocaps == NULL) {
GST_DEBUG (0,"gstcaps: no caps\n"); GST_DEBUG (GST_CAT_CAPS,"no caps\n");
return TRUE; return TRUE;
} }
else { else {
GST_DEBUG (0,"gstcaps: no src but destination caps\n"); GST_DEBUG (GST_CAT_CAPS,"no source but destination caps\n");
return FALSE; return FALSE;
} }
} }
else { else {
if (tocaps == NULL) { if (tocaps == NULL) {
GST_DEBUG (0,"gstcaps: src caps and no dest caps\n"); GST_DEBUG (GST_CAT_CAPS,"source caps and no destination caps\n");
return TRUE; return TRUE;
} }
} }

View file

@ -71,7 +71,7 @@ void
gst_clock_register (GstClock *clock, GstObject *obj) gst_clock_register (GstClock *clock, GstObject *obj)
{ {
if ((GST_ELEMENT(obj))->numsrcpads == 0) { if ((GST_ELEMENT(obj))->numsrcpads == 0) {
GST_DEBUG (0,"gst_clock: setting registered sink object 0x%p\n", obj); GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting registered sink object 0x%p\n", obj);
clock->sinkobjects = g_list_append (clock->sinkobjects, obj); clock->sinkobjects = g_list_append (clock->sinkobjects, obj);
clock->num++; clock->num++;
} }
@ -88,7 +88,8 @@ gst_clock_set (GstClock *clock, GstClockTime time)
g_mutex_lock (clock->lock); g_mutex_lock (clock->lock);
clock->start_time = now - time; clock->start_time = now - time;
g_mutex_unlock (clock->lock); g_mutex_unlock (clock->lock);
GST_DEBUG (0,"gst_clock: setting clock to %llu %llu %llu\n", time, now, clock->start_time); GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting clock to %llu %llu %llu\n",
time, now, clock->start_time);
} }
GstClockTimeDiff GstClockTimeDiff
@ -115,7 +116,7 @@ gst_clock_reset (GstClock *clock)
clock->start_time = ((guint64)tfnow.tv_sec)*1000000LL+tfnow.tv_usec; clock->start_time = ((guint64)tfnow.tv_sec)*1000000LL+tfnow.tv_usec;
clock->current_time = clock->start_time; clock->current_time = clock->start_time;
clock->adjust = 0LL; clock->adjust = 0LL;
GST_DEBUG (0,"gst_clock: setting start clock %llu\n", clock->start_time); GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting start clock %llu\n", clock->start_time);
g_mutex_unlock (clock->lock); g_mutex_unlock (clock->lock);
} }
@ -133,7 +134,8 @@ gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj)
diff = GST_CLOCK_DIFF (time, now); diff = GST_CLOCK_DIFF (time, now);
// if we are not behind wait a bit // if we are not behind wait a bit
GST_DEBUG (0,"gst_clock: %s waiting for time %08llu %08llu %08lld\n", GST_OBJECT_NAME (obj), time, now, diff); GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld\n",
GST_OBJECT_NAME (obj), time, now, diff);
g_mutex_unlock (clock->lock); g_mutex_unlock (clock->lock);
if (diff > 10000 ) { if (diff > 10000 ) {
@ -143,8 +145,9 @@ gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj)
if (!tfnow.tv_sec) { if (!tfnow.tv_sec) {
select(0, NULL, NULL, NULL, &tfnow); select(0, NULL, NULL, NULL, &tfnow);
} }
else GST_DEBUG (0,"gst_clock: %s waiting %u %llu %llu %llu seconds\n", GST_OBJECT_NAME (obj), else GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting %u %llu %llu %llu seconds\n",
(int)tfnow.tv_sec, now, diff, time); GST_OBJECT_NAME (obj), (int)tfnow.tv_sec, now, diff, time);
} }
GST_DEBUG (0,"gst_clock: %s waiting for time %08llu %08llu %08lld done \n", GST_OBJECT_NAME (obj), time, now, diff); GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld done \n",
GST_OBJECT_NAME (obj), time, now, diff);
} }

View file

@ -26,14 +26,16 @@
#include "gstelement.h" #include "gstelement.h"
#include "gstextratypes.h" #include "gstextratypes.h"
#include "gstbin.h" #include "gstbin.h"
#include "gstscheduler.h"
#include "gstutils.h" #include "gstutils.h"
/* Element signals and args */ /* Element signals and args */
enum { enum {
STATE_CHANGE, STATE_CHANGE,
NEW_PAD, NEW_PAD,
PAD_REMOVED,
NEW_GHOST_PAD, NEW_GHOST_PAD,
GHOST_PAD_REMOVED,
ERROR, ERROR,
EOS, EOS,
LAST_SIGNAL LAST_SIGNAL
@ -48,6 +50,10 @@ enum {
static void gst_element_class_init (GstElementClass *klass); static void gst_element_class_init (GstElementClass *klass);
static void gst_element_init (GstElement *element); static void gst_element_init (GstElement *element);
static void gst_element_set_arg (GtkObject *object, GtkArg *arg, guint id);
static void gst_element_get_arg (GtkObject *object, GtkArg *arg, guint id);
static void gst_element_shutdown (GtkObject *object);
static void gst_element_real_destroy (GtkObject *object); static void gst_element_real_destroy (GtkObject *object);
static GstElementStateReturn gst_element_change_state (GstElement *element); static GstElementStateReturn gst_element_change_state (GstElement *element);
@ -67,8 +73,8 @@ GtkType gst_element_get_type(void) {
sizeof(GstElementClass), sizeof(GstElementClass),
(GtkClassInitFunc)gst_element_class_init, (GtkClassInitFunc)gst_element_class_init,
(GtkObjectInitFunc)gst_element_init, (GtkObjectInitFunc)gst_element_init,
(GtkArgSetFunc)NULL, (GtkArgSetFunc)gst_element_set_arg,
(GtkArgGetFunc)NULL, (GtkArgGetFunc)gst_element_get_arg,
(GtkClassInitFunc)NULL, (GtkClassInitFunc)NULL,
}; };
element_type = gtk_type_unique(GST_TYPE_OBJECT,&element_info); element_type = gtk_type_unique(GST_TYPE_OBJECT,&element_info);
@ -97,11 +103,21 @@ gst_element_class_init (GstElementClass *klass)
GTK_SIGNAL_OFFSET (GstElementClass, new_pad), GTK_SIGNAL_OFFSET (GstElementClass, new_pad),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GST_TYPE_PAD); GST_TYPE_PAD);
gst_element_signals[PAD_REMOVED] =
gtk_signal_new ("pad_removed", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstElementClass, pad_removed),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GST_TYPE_PAD);
gst_element_signals[NEW_GHOST_PAD] = gst_element_signals[NEW_GHOST_PAD] =
gtk_signal_new ("new_ghost_pad", GTK_RUN_LAST, gtkobject_class->type, gtk_signal_new ("new_ghost_pad", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstElementClass, new_ghost_pad), GTK_SIGNAL_OFFSET (GstElementClass, new_ghost_pad),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GST_TYPE_PAD); GST_TYPE_PAD);
gst_element_signals[GHOST_PAD_REMOVED] =
gtk_signal_new ("ghost_pad_removed", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstElementClass, ghost_pad_removed),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GST_TYPE_PAD);
gst_element_signals[ERROR] = gst_element_signals[ERROR] =
gtk_signal_new ("error", GTK_RUN_LAST, gtkobject_class->type, gtk_signal_new ("error", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstElementClass, error), GTK_SIGNAL_OFFSET (GstElementClass, error),
@ -115,11 +131,15 @@ gst_element_class_init (GstElementClass *klass)
gtk_object_class_add_signals (gtkobject_class, gst_element_signals, LAST_SIGNAL); gtk_object_class_add_signals (gtkobject_class, gst_element_signals, LAST_SIGNAL);
gtkobject_class->destroy = gst_element_real_destroy; gtkobject_class->set_arg = GST_DEBUG_FUNCPTR(gst_element_set_arg);
gtkobject_class->get_arg = GST_DEBUG_FUNCPTR(gst_element_get_arg);
gtkobject_class->shutdown = GST_DEBUG_FUNCPTR(gst_element_shutdown);
gtkobject_class->destroy = GST_DEBUG_FUNCPTR(gst_element_real_destroy);
gstobject_class->save_thyself = gst_element_save_thyself; gstobject_class->save_thyself = GST_DEBUG_FUNCPTR(gst_element_save_thyself);
gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR(gst_element_restore_thyself);
klass->change_state = gst_element_change_state; klass->change_state = GST_DEBUG_FUNCPTR(gst_element_change_state);
klass->elementfactory = NULL; klass->elementfactory = NULL;
} }
@ -134,8 +154,38 @@ gst_element_init (GstElement *element)
element->pads = NULL; element->pads = NULL;
element->loopfunc = NULL; element->loopfunc = NULL;
element->threadstate = NULL; element->threadstate = NULL;
element->sched = NULL;
} }
static void
gst_element_set_arg (GtkObject *object, GtkArg *arg, guint id)
{
GstElementClass *oclass = GST_ELEMENT_CLASS (object->klass);
GST_SCHEDULE_LOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
if (oclass->set_arg)
(oclass->set_arg)(object,arg,id);
GST_SCHEDULE_UNLOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
}
static void
gst_element_get_arg (GtkObject *object, GtkArg *arg, guint id)
{
GstElementClass *oclass = GST_ELEMENT_CLASS (object->klass);
GST_SCHEDULE_LOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
if (oclass->get_arg)
(oclass->get_arg)(object,arg,id);
GST_SCHEDULE_UNLOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
}
/** /**
* gst_element_new: * gst_element_new:
* *
@ -237,9 +287,15 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
g_return_if_fail (pad != NULL); g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (GST_IS_PAD (pad));
// first check to make sure the pad's parent is already set
g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
// then check to see if there's already a pad by that name here
g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
/* set the pad's parent */ /* set the pad's parent */
GST_DEBUG (0,"setting parent of pad '%s'(%p) to '%s'(%p)\n", GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'\n",
GST_PAD_NAME (pad), pad, GST_ELEMENT_NAME (element), element); GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element)); gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
/* add it to the list */ /* add it to the list */
@ -254,6 +310,36 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_PAD], pad); gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_PAD], pad);
} }
/**
* gst_element_remove_pad:
* @element: element to remove pad from
* @pad: pad to remove
*
* Remove a pad (connection point) from the element,
*/
void
gst_element_remove_pad (GstElement *element, GstPad *pad)
{
g_return_if_fail (element != NULL);
g_return_if_fail (GST_IS_ELEMENT (element));
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (GST_PAD_PARENT (pad) == element);
/* add it to the list */
element->pads = g_list_remove (element->pads, pad);
element->numpads--;
if (gst_pad_get_direction (pad) == GST_PAD_SRC)
element->numsrcpads--;
else
element->numsinkpads--;
gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[PAD_REMOVED], pad);
gst_object_unparent (GST_OBJECT (pad));
}
/** /**
* gst_element_add_ghost_pad: * gst_element_add_ghost_pad:
* @element: element to add ghost pad to * @element: element to add ghost pad to
@ -273,17 +359,22 @@ gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name)
g_return_if_fail (pad != NULL); g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (GST_IS_PAD (pad));
GST_DEBUG(0,"creating new ghost pad called %s, from pad %s:%s\n",name,GST_DEBUG_PAD_NAME(pad)); // then check to see if there's already a pad by that name here
g_return_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE);
GST_DEBUG(GST_CAT_ELEMENT_PADS,"creating new ghost pad called %s, from pad %s:%s\n",
name,GST_DEBUG_PAD_NAME(pad));
ghostpad = gst_ghost_pad_new (name, pad); ghostpad = gst_ghost_pad_new (name, pad);
/* add it to the list */ /* add it to the list */
GST_DEBUG(0,"adding ghost pad %s to element %s\n", name, GST_ELEMENT_NAME (element)); GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s\n",
name, GST_ELEMENT_NAME (element));
element->pads = g_list_append (element->pads, ghostpad); element->pads = g_list_append (element->pads, ghostpad);
element->numpads++; element->numpads++;
// set the parent of the ghostpad // set the parent of the ghostpad
gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element)); gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
GST_DEBUG(0,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad)); GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
/* emit the NEW_GHOST_PAD signal */ /* emit the NEW_GHOST_PAD signal */
gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_GHOST_PAD], ghostpad); gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_GHOST_PAD], ghostpad);
@ -331,21 +422,18 @@ gst_element_get_pad (GstElement *element, const gchar *name)
if (!element->numpads) if (!element->numpads)
return NULL; return NULL;
GST_DEBUG(GST_CAT_ELEMENT_PADS,"searching for pad '%s' in element %s\n",
name, GST_ELEMENT_NAME (element));
// look through the list, matching by name // look through the list, matching by name
walk = element->pads; walk = element->pads;
while (walk) { while (walk) {
GstPad *pad = GST_PAD(walk->data); GstPad *pad = GST_PAD(walk->data);
if (!strcmp (gst_object_get_name (GST_OBJECT(pad)), name)) { if (!strcmp (GST_PAD_NAME(pad), name)) {
GST_DEBUG(GST_CAT_ELEMENT_PADS,"found pad '%s'\n",name); GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad));
return pad; return pad;
} }
walk = g_list_next (walk); walk = g_list_next (walk);
} }
GST_DEBUG(GST_CAT_ELEMENT_PADS,"no such pad '%s'\n",name); GST_INFO(GST_CAT_ELEMENT_PADS,"no such pad '%s' in element \"%s\"",name,GST_ELEMENT_NAME(element));
return NULL; return NULL;
} }
@ -440,7 +528,7 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *
GstPadTemplate *newtempl = NULL; GstPadTemplate *newtempl = NULL;
GList *padlist; GList *padlist;
GST_DEBUG(0,"gst_element_get_padtemplate_by_compatible()\n"); GST_DEBUG(GST_CAT_ELEMENT_PADS,"gst_element_get_padtemplate_by_compatible()\n");
g_return_val_if_fail (element != NULL, NULL); g_return_val_if_fail (element != NULL, NULL);
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
@ -457,19 +545,19 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *
// Check direction (must be opposite) // Check direction (must be opposite)
// Check caps // Check caps
GST_DEBUG(0,"checking direction and caps\n"); GST_DEBUG(GST_CAT_CAPS,"checking direction and caps\n");
if (padtempl->direction == GST_PAD_SRC && if (padtempl->direction == GST_PAD_SRC &&
compattempl->direction == GST_PAD_SINK) { compattempl->direction == GST_PAD_SINK) {
GST_DEBUG(0,"compatible direction: found src pad template\n"); GST_DEBUG(GST_CAT_CAPS,"compatible direction: found src pad template\n");
compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (padtempl), compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (padtempl),
GST_PADTEMPLATE_CAPS (compattempl)); GST_PADTEMPLATE_CAPS (compattempl));
GST_DEBUG(0,"caps are %scompatible\n", (compat?"":"not ")); GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
} else if (padtempl->direction == GST_PAD_SINK && } else if (padtempl->direction == GST_PAD_SINK &&
compattempl->direction == GST_PAD_SRC) { compattempl->direction == GST_PAD_SRC) {
GST_DEBUG(0,"compatible direction: found sink pad template\n"); GST_DEBUG(GST_CAT_CAPS,"compatible direction: found sink pad template\n");
compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (compattempl), compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (compattempl),
GST_PADTEMPLATE_CAPS (padtempl)); GST_PADTEMPLATE_CAPS (padtempl));
GST_DEBUG(0,"caps are %scompatible\n", (compat?"":"not ")); GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
} }
if (compat) { if (compat) {
@ -659,7 +747,7 @@ gst_element_disconnect (GstElement *src, const gchar *srcpadname,
void void
gst_element_error (GstElement *element, const gchar *error) gst_element_error (GstElement *element, const gchar *error)
{ {
g_error("GstElement: error in element '%s': %s\n", gst_object_get_name (GST_OBJECT (element)), error); g_error("GstElement: error in element '%s': %s\n", GST_ELEMENT_NAME(element), error);
/* FIXME: this is not finished!!! */ /* FIXME: this is not finished!!! */
@ -689,6 +777,11 @@ gst_element_set_state (GstElement *element, GstElementState state)
g_return_val_if_fail (element != NULL, GST_STATE_FAILURE); g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE); g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
g_return_val_if_fail (element->sched != NULL, GST_STATE_FAILURE);
GST_DEBUG_ELEMENT (GST_CAT_STATES,element, "setting state from %s to %s\n",
gst_element_statename(GST_STATE(element)),
gst_element_statename(state));
/* start with the current state */ /* start with the current state */
curpending = GST_STATE(element); curpending = GST_STATE(element);
@ -702,6 +795,9 @@ gst_element_set_state (GstElement *element, GstElementState state)
/* set the pending state variable */ /* set the pending state variable */
// FIXME: should probably check to see that we don't already have one // FIXME: should probably check to see that we don't already have one
GST_STATE_PENDING (element) = curpending; GST_STATE_PENDING (element) = curpending;
if (curpending != state)
GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"intermediate: setting state to %s\n",
gst_element_statename(curpending));
/* call the state change function so it can set the state */ /* call the state change function so it can set the state */
oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass); oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
@ -711,7 +807,7 @@ gst_element_set_state (GstElement *element, GstElementState state)
/* if that outright didn't work, we need to bail right away */ /* if that outright didn't work, we need to bail right away */
/* NOTE: this will bail on ASYNC as well! */ /* NOTE: this will bail on ASYNC as well! */
if (return_val == GST_STATE_FAILURE) { if (return_val == GST_STATE_FAILURE) {
// GST_DEBUG (0,"have async return from '%s'\n",GST_ELEMENT_NAME (element)); GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"have failed change_state return\n");
return return_val; return return_val;
} }
} }
@ -741,6 +837,7 @@ gst_element_get_factory (GstElement *element)
return oclass->elementfactory; return oclass->elementfactory;
} }
/** /**
* gst_element_change_state: * gst_element_change_state:
* @element: element to change state of * @element: element to change state of
@ -757,15 +854,48 @@ gst_element_change_state (GstElement *element)
g_return_val_if_fail (element != NULL, GST_STATE_FAILURE); g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE); g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
// g_print("gst_element_change_state(\"%s\",%d)\n", // GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "default handler sets state to %s\n",
// element->name,state); // gst_element_statename(GST_STATE_PENDING(element)));
if (GST_STATE_TRANSITION(element) == GST_STATE_PAUSED_TO_PLAYING) {
g_return_val_if_fail(GST_ELEMENT_SCHED(element), GST_STATE_FAILURE);
if (GST_ELEMENT_PARENT(element))
fprintf(stderr,"PAUSED->PLAYING: element \"%s\" has parent \"%s\" and sched %p\n",
GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
GST_SCHEDULE_ENABLE_ELEMENT (element->sched,element);
}
else if (GST_STATE_TRANSITION(element) == GST_STATE_PLAYING_TO_PAUSED) {
if (GST_ELEMENT_PARENT(element))
fprintf(stderr,"PLAYING->PAUSED: element \"%s\" has parent \"%s\" and sched %p\n",
GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
GST_SCHEDULE_DISABLE_ELEMENT (element->sched,element);
}
GST_STATE (element) = GST_STATE_PENDING (element); GST_STATE (element) = GST_STATE_PENDING (element);
GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING; GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING;
// note: queues' state_change is a special case because it needs to lock
// for synchronization (from another thread). since this signal may block
// or (worse) make another state change, the queue needs to unlock before
// calling. thus, gstqueue.c::gst_queue_state_change() blocks, unblocks,
// unlocks, then emits this.
gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[STATE_CHANGE], gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[STATE_CHANGE],
GST_STATE (element)); GST_STATE (element));
return TRUE; return GST_STATE_SUCCESS;
}
static void
gst_element_shutdown (GtkObject *object)
{
GstElement *element = GST_ELEMENT (object);
GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "shutdown\n");
if (GST_IS_BIN (GST_OBJECT_PARENT (element)))
gst_bin_remove (GST_BIN (GST_OBJECT_PARENT (element)), element);
if (GTK_OBJECT_CLASS (parent_class)->shutdown)
GTK_OBJECT_CLASS (parent_class)->shutdown (object);
} }
static void static void
@ -775,16 +905,29 @@ gst_element_real_destroy (GtkObject *object)
GList *pads; GList *pads;
GstPad *pad; GstPad *pad;
// g_print("in gst_element_real_destroy()\n"); GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "destroy\n");
pads = element->pads; if (element->pads) {
while (pads) { GList *orig;
pad = GST_PAD (pads->data); orig = pads = g_list_copy (element->pads);
gst_pad_destroy (pad); while (pads) {
pads = g_list_next (pads); pad = GST_PAD (pads->data);
//gst_object_destroy (GST_OBJECT (pad));
gst_object_ref (GST_OBJECT (pad));
gst_element_remove_pad (element, pad);
gst_object_unref (GST_OBJECT (pad));
pads = g_list_next (pads);
}
g_list_free (orig);
g_list_free (element->pads);
element->pads = NULL;
} }
g_list_free (element->pads); element->numsrcpads = 0;
element->numsinkpads = 0;
if (GTK_OBJECT_CLASS (parent_class)->destroy)
GTK_OBJECT_CLASS (parent_class)->destroy (object);
} }
/* /*
@ -830,7 +973,7 @@ gst_element_save_thyself (GstObject *object,
oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass); oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
xmlNewChild(parent, NULL, "name", gst_object_get_name (GST_OBJECT (element))); xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
if (oclass->elementfactory != NULL) { if (oclass->elementfactory != NULL) {
GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory; GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
@ -839,6 +982,9 @@ gst_element_save_thyself (GstObject *object,
xmlNewChild (parent, NULL, "version", factory->details->version); xmlNewChild (parent, NULL, "version", factory->details->version);
} }
// if (element->manager)
// xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager));
// output all args to the element // output all args to the element
type = GTK_OBJECT_TYPE (element); type = GTK_OBJECT_TYPE (element);
while (type != GTK_TYPE_INVALID) { while (type != GTK_TYPE_INVALID) {
@ -918,7 +1064,7 @@ gst_element_save_thyself (GstObject *object,
} }
/** /**
* gst_element_load_thyself: * gst_element_restore_thyself:
* @self: the xml node * @self: the xml node
* @parent: the parent of this object when it's loaded * @parent: the parent of this object when it's loaded
* *
@ -927,7 +1073,7 @@ gst_element_save_thyself (GstObject *object,
* Returns: the new element * Returns: the new element
*/ */
GstElement* GstElement*
gst_element_load_thyself (xmlNodePtr self, GstObject *parent) gst_element_restore_thyself (xmlNodePtr self, GstObject *parent)
{ {
xmlNodePtr children = self->xmlChildrenNode; xmlNodePtr children = self->xmlChildrenNode;
GstElement *element; GstElement *element;
@ -948,7 +1094,7 @@ gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (type != NULL, NULL); g_return_val_if_fail (type != NULL, NULL);
GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"\n", name, type); GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"", name, type);
element = gst_elementfactory_make (type, name); element = gst_elementfactory_make (type, name);
@ -1002,32 +1148,33 @@ gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
} }
/** /**
* gst_element_set_manager: * gst_element_set_sched:
* @element: Element to set manager of. * @element: Element to set manager of.
* @manager: Element to be the manager. * @sched: @GstSchedule to set.
* *
* Sets the manager of the element. For internal use only, unless you're * Sets the scheduler of the element. For internal use only, unless you're
* writing a new bin subclass. * writing a new bin subclass.
*/ */
void void
gst_element_set_manager (GstElement *element, gst_element_set_sched (GstElement *element,
GstElement *manager) GstSchedule *sched)
{ {
element->manager = manager; GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p",sched);
element->sched = sched;
} }
/** /**
* gst_element_get_manager: * gst_element_get_sched:
* @element: Element to get manager of. * @element: Element to get manager of.
* *
* Returns the manager of the element. * Returns the scheduler of the element.
* *
* Returns: Element's manager * Returns: Element's scheduler
*/ */
GstElement* GstSchedule*
gst_element_get_manager (GstElement *element) gst_element_get_sched (GstElement *element)
{ {
return element->manager; return element->sched;
} }
/** /**
@ -1070,3 +1217,24 @@ gst_element_signal_eos (GstElement *element)
GST_FLAG_SET(element,GST_ELEMENT_COTHREAD_STOPPING); GST_FLAG_SET(element,GST_ELEMENT_COTHREAD_STOPPING);
} }
const gchar *gst_element_statename(int state) {
switch (state) {
#ifdef GST_DEBUG_COLOR
case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
default: return "\033[01;37;41mUNKNOWN!\033[00m";
#else
case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
case GST_STATE_NULL: return "NULL";break;
case GST_STATE_READY: return "READY";break;
case GST_STATE_PLAYING: return "PLAYING";break;
case GST_STATE_PAUSED: return "PAUSED";break;
default: return "UNKNOWN!";
#endif
}
return "";
}

View file

@ -46,8 +46,8 @@ typedef enum {
GST_STATE_NONE_PENDING = 0, GST_STATE_NONE_PENDING = 0,
GST_STATE_NULL = (1 << 0), GST_STATE_NULL = (1 << 0),
GST_STATE_READY = (1 << 1), GST_STATE_READY = (1 << 1),
GST_STATE_PLAYING = (1 << 2), GST_STATE_PAUSED = (1 << 2),
GST_STATE_PAUSED = (1 << 3), GST_STATE_PLAYING = (1 << 3),
} GstElementState; } GstElementState;
typedef enum { typedef enum {
@ -56,28 +56,19 @@ typedef enum {
GST_STATE_ASYNC = 2, GST_STATE_ASYNC = 2,
} GstElementStateReturn; } GstElementStateReturn;
static inline char *_gst_print_statename(int state) {
switch (state) {
case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
case GST_STATE_NULL: return "NULL";break;
case GST_STATE_READY: return "READY";break;
case GST_STATE_PLAYING: return "PLAYING";break;
case GST_STATE_PAUSED: return "PAUSED";break;
default: return "";
}
return "";
}
// NOTE: this probably should be done with an #ifdef to decide whether to safe-cast
// or to just do the non-checking cast.
#define GST_STATE(obj) (GST_ELEMENT(obj)->current_state) #define GST_STATE(obj) (GST_ELEMENT(obj)->current_state)
#define GST_STATE_PENDING(obj) (GST_ELEMENT(obj)->pending_state) #define GST_STATE_PENDING(obj) (GST_ELEMENT(obj)->pending_state)
// Note: using 8 bit shift mostly "just because", it leaves us enough room to grow <g> // Note: using 8 bit shift mostly "just because", it leaves us enough room to grow <g>
#define GST_STATE_TRANSITION(obj) ((GST_STATE(obj)<<8) | GST_STATE_PENDING(obj)) #define GST_STATE_TRANSITION(obj) ((GST_STATE(obj)<<8) | GST_STATE_PENDING(obj))
#define GST_STATE_NULL_TO_READY ((GST_STATE_NULL<<8) | GST_STATE_READY) #define GST_STATE_NULL_TO_READY ((GST_STATE_NULL<<8) | GST_STATE_READY)
#define GST_STATE_READY_TO_PLAYING ((GST_STATE_READY<<8) | GST_STATE_PLAYING) #define GST_STATE_READY_TO_PAUSED ((GST_STATE_READY<<8) | GST_STATE_PAUSED)
#define GST_STATE_PLAYING_TO_PAUSED ((GST_STATE_PLAYING<<8) | GST_STATE_PAUSED)
#define GST_STATE_PAUSED_TO_PLAYING ((GST_STATE_PAUSED<<8) | GST_STATE_PLAYING) #define GST_STATE_PAUSED_TO_PLAYING ((GST_STATE_PAUSED<<8) | GST_STATE_PLAYING)
#define GST_STATE_PLAYING_TO_READY ((GST_STATE_PLAYING<<8) | GST_STATE_READY) #define GST_STATE_PLAYING_TO_PAUSED ((GST_STATE_PLAYING<<8) | GST_STATE_PAUSED)
#define GST_STATE_PAUSED_TO_READY ((GST_STATE_PAUSED<<8) | GST_STATE_READY)
#define GST_STATE_READY_TO_NULL ((GST_STATE_READY<<8) | GST_STATE_NULL) #define GST_STATE_READY_TO_NULL ((GST_STATE_READY<<8) | GST_STATE_NULL)
#define GST_TYPE_ELEMENT \ #define GST_TYPE_ELEMENT \
@ -104,6 +95,9 @@ typedef enum {
/***** !!!!! need to have a flag that says that an element must /***** !!!!! need to have a flag that says that an element must
*not* be an entry into a scheduling chain !!!!! *****/ *not* be an entry into a scheduling chain !!!!! *****/
/* this element for some reason doesn't obey COTHREAD_STOPPING, or
has some other reason why it can't be the entry */
GST_ELEMENT_NO_ENTRY,
/* there is a new loopfunction ready for placement */ /* there is a new loopfunction ready for placement */
GST_ELEMENT_NEW_LOOPFUNC, GST_ELEMENT_NEW_LOOPFUNC,
@ -116,7 +110,7 @@ typedef enum {
GST_ELEMENT_EOS, GST_ELEMENT_EOS,
/* use some padding for future expansion */ /* use some padding for future expansion */
GST_ELEMENT_FLAG_LAST = GST_OBJECT_FLAG_LAST + 8, GST_ELEMENT_FLAG_LAST = GST_OBJECT_FLAG_LAST + 12,
} GstElementFlags; } GstElementFlags;
#define GST_ELEMENT_IS_THREAD_SUGGESTED(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_THREAD_SUGGESTED)) #define GST_ELEMENT_IS_THREAD_SUGGESTED(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_THREAD_SUGGESTED))
@ -125,10 +119,12 @@ typedef enum {
#define GST_ELEMENT_NAME(obj) (GST_OBJECT_NAME(obj)) #define GST_ELEMENT_NAME(obj) (GST_OBJECT_NAME(obj))
#define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj)) #define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj))
#define GST_ELEMENT_MANAGER(obj) (((GstElement*)(obj))->manager)
#define GST_ELEMENT_SCHED(obj) (((GstElement*)(obj))->sched)
#define GST_ELEMENT_PADS(obj) ((obj)->pads) #define GST_ELEMENT_PADS(obj) ((obj)->pads)
typedef struct _GstElement GstElement; //typedef struct _GstElement GstElement;
typedef struct _GstElementClass GstElementClass; //typedef struct _GstElementClass GstElementClass;
typedef struct _GstElementDetails GstElementDetails; typedef struct _GstElementDetails GstElementDetails;
typedef struct _GstElementFactory GstElementFactory; typedef struct _GstElementFactory GstElementFactory;
@ -149,6 +145,7 @@ struct _GstElement {
GList *pads; GList *pads;
GstElement *manager; GstElement *manager;
GstSchedule *sched;
}; };
struct _GstElementClass { struct _GstElementClass {
@ -158,11 +155,21 @@ struct _GstElementClass {
GstElementFactory *elementfactory; GstElementFactory *elementfactory;
/* signal callbacks */ /* signal callbacks */
void (*state_change) (GstElement *element,GstElementState state); void (*state_change) (GstElement *element,GstElementState state);
void (*new_pad) (GstElement *element,GstPad *pad); void (*new_pad) (GstElement *element,GstPad *pad);
void (*new_ghost_pad) (GstElement *element,GstPad *pad); void (*pad_removed) (GstElement *element,GstPad *pad);
void (*error) (GstElement *element,gchar *error); void (*new_ghost_pad) (GstElement *element,GstPad *pad);
void (*eos) (GstElement *element); void (*ghost_pad_removed) (GstElement *element,GstPad *pad);
void (*error) (GstElement *element,gchar *error);
void (*eos) (GstElement *element);
/* local pointers for get/set */
void (*set_arg) (GtkObject *object,
GtkArg *arg,
guint arg_id);
void (*get_arg) (GtkObject *object,
GtkArg *arg,
guint arg_id);
/* change the element state */ /* change the element state */
GstElementStateReturn (*change_state) (GstElement *element); GstElementStateReturn (*change_state) (GstElement *element);
@ -202,10 +209,11 @@ const gchar* gst_element_get_name (GstElement *element);
void gst_element_set_parent (GstElement *element, GstObject *parent); void gst_element_set_parent (GstElement *element, GstObject *parent);
GstObject* gst_element_get_parent (GstElement *element); GstObject* gst_element_get_parent (GstElement *element);
void gst_element_set_manager (GstElement *element, GstElement *manager); void gst_element_set_sched (GstElement *element, GstSchedule *sched);
GstElement* gst_element_get_manager (GstElement *element); GstSchedule* gst_element_get_sched (GstElement *element);
void gst_element_add_pad (GstElement *element, GstPad *pad); void gst_element_add_pad (GstElement *element, GstPad *pad);
void gst_element_remove_pad (GstElement *element, GstPad *pad);
GstPad* gst_element_get_pad (GstElement *element, const gchar *name); GstPad* gst_element_get_pad (GstElement *element, const gchar *name);
GList* gst_element_get_pad_list (GstElement *element); GList* gst_element_get_pad_list (GstElement *element);
GList* gst_element_get_padtemplate_list (GstElement *element); GList* gst_element_get_padtemplate_list (GstElement *element);
@ -232,7 +240,7 @@ void gst_element_error (GstElement *element, const gchar *error);
GstElementFactory* gst_element_get_factory (GstElement *element); GstElementFactory* gst_element_get_factory (GstElement *element);
/* XML write and read */ /* XML write and read */
GstElement* gst_element_load_thyself (xmlNodePtr self, GstObject *parent); GstElement* gst_element_restore_thyself (xmlNodePtr self, GstObject *parent);
/* /*
@ -264,9 +272,13 @@ GstElement* gst_elementfactory_create (GstElementFactory *factory,
/* FIXME this name is wrong, probably so is the one above it */ /* FIXME this name is wrong, probably so is the one above it */
GstElement* gst_elementfactory_make (const gchar *factoryname, const gchar *name); GstElement* gst_elementfactory_make (const gchar *factoryname, const gchar *name);
xmlNodePtr gst_elementfactory_save_thyself (GstElementFactory *factory, xmlNodePtr parent); xmlNodePtr gst_elementfactory_save_thyself (GstElementFactory *factory, xmlNodePtr parent);
GstElementFactory* gst_elementfactory_load_thyself (xmlNodePtr parent); GstElementFactory* gst_elementfactory_load_thyself (xmlNodePtr parent);
const gchar * gst_element_statename (int state);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View file

@ -68,8 +68,6 @@ gst_elementfactory_find (const gchar *name)
g_return_val_if_fail(name != NULL, NULL); g_return_val_if_fail(name != NULL, NULL);
GST_DEBUG (0,"gstelementfactory: find \"%s\"\n", name);
walk = _gst_elementfactories; walk = _gst_elementfactories;
while (walk) { while (walk) {
factory = (GstElementFactory *)(walk->data); factory = (GstElementFactory *)(walk->data);
@ -78,6 +76,8 @@ gst_elementfactory_find (const gchar *name)
walk = g_list_next(walk); walk = g_list_next(walk);
} }
// this should be an ERROR
GST_DEBUG (GST_CAT_ELEMENTFACTORY,"no such elementfactoryfactory \"%s\"\n", name);
return NULL; return NULL;
} }
@ -148,7 +148,8 @@ gst_elementfactory_create (GstElementFactory *factory,
g_return_val_if_fail(factory != NULL, NULL); g_return_val_if_fail(factory != NULL, NULL);
g_return_val_if_fail(name != NULL, NULL); g_return_val_if_fail(name != NULL, NULL);
GST_DEBUG (0,"gstelementfactory: create \"%s\" \"%s\"\n", factory->name, name); GST_DEBUG (GST_CAT_ELEMENTFACTORY,"creating element from factory \"%s\" with name \"%s\"\n",
factory->name, name);
// it's not loaded, try to load the plugin // it's not loaded, try to load the plugin
if (factory->type == 0) { if (factory->type == 0) {
@ -160,12 +161,11 @@ gst_elementfactory_create (GstElementFactory *factory,
// create an instance of the element // create an instance of the element
element = GST_ELEMENT(gtk_type_new(factory->type)); element = GST_ELEMENT(gtk_type_new(factory->type));
g_assert(element != NULL); g_assert(element != NULL);
gst_object_ref(GST_OBJECT(element));
// attempt to set the elemenfactory class pointer if necessary // attempt to set the elemenfactory class pointer if necessary
oclass = GST_ELEMENT_CLASS(GTK_OBJECT(element)->klass); oclass = GST_ELEMENT_CLASS(GTK_OBJECT(element)->klass);
if (oclass->elementfactory == NULL) { if (oclass->elementfactory == NULL) {
GST_DEBUG (0,"gstelementfactory: class %s\n", factory->name); GST_DEBUG (GST_CAT_ELEMENTFACTORY,"class %s\n", factory->name);
oclass->elementfactory = factory; oclass->elementfactory = factory;
} }
@ -194,7 +194,7 @@ gst_elementfactory_make (const gchar *factoryname, const gchar *name)
g_return_val_if_fail(factoryname != NULL, NULL); g_return_val_if_fail(factoryname != NULL, NULL);
g_return_val_if_fail(name != NULL, NULL); g_return_val_if_fail(name != NULL, NULL);
GST_DEBUG (0,"gstelementfactory: make \"%s\" \"%s\"\n", factoryname, name); // GST_DEBUG (GST_CAT_ELEMENTFACTORY,"gstelementfactory: make \"%s\" \"%s\"\n", factoryname, name);
//gst_plugin_load_elementfactory(factoryname); //gst_plugin_load_elementfactory(factoryname);
factory = gst_elementfactory_find(factoryname); factory = gst_elementfactory_find(factoryname);

View file

@ -20,6 +20,7 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#include <dlfcn.h>
#include "gst_private.h" #include "gst_private.h"
#include "gstelement.h" #include "gstelement.h"
#include "gstpad.h" #include "gstpad.h"
@ -27,19 +28,7 @@
extern gchar *_gst_progname; extern gchar *_gst_progname;
/***** DEBUG system *****/ /***** Categories and colorization *****/
GHashTable *__gst_function_pointers = NULL;
/***** INFO system *****/
GstInfoHandler _gst_info_handler = gst_default_info_handler;
#ifdef GST_INFO_ENABLED_VERBOSE
guint32 _gst_info_categories = 0xffffffff;
#else
guint32 _gst_info_categories = 0x00000001;
#endif
static gchar *_gst_info_category_strings[] = { static gchar *_gst_info_category_strings[] = {
"GST_INIT", "GST_INIT",
"COTHREADS", "COTHREADS",
@ -48,9 +37,9 @@ static gchar *_gst_info_category_strings[] = {
"AUTOPLUG_ATTEMPT", "AUTOPLUG_ATTEMPT",
"PARENTAGE", "PARENTAGE",
"STATES", "STATES",
"PLANING", "PLANNING",
"SCHEDULING", "SCHEDULING",
"OPERATION", "DATAFLOW",
"BUFFER", "BUFFER",
"CAPS", "CAPS",
"CLOCK", "CLOCK",
@ -66,48 +55,195 @@ static gchar *_gst_info_category_strings[] = {
"TYPES", "TYPES",
"XML", "XML",
"NEGOTIATION", "NEGOTIATION",
"REFCOUNTING",
}; };
const gchar *_gst_category_colors[] = { /**
[GST_CAT_GST_INIT] = "00;37", * gst_get_category_name:
[GST_CAT_COTHREADS] = "00;32", * @category: the category to return the name of
[GST_CAT_COTHREAD_SWITCH] = "00;32", *
[GST_CAT_AUTOPLUG] = "00;34", * Returns: string containing the name of the category
[GST_CAT_AUTOPLUG_ATTEMPT] = "00;34", */
[GST_CAT_PARENTAGE] = "", const gchar *
[GST_CAT_STATES] = "00;31", gst_get_category_name (gint category) {
[GST_CAT_PLANNING] = "00;35", if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
[GST_CAT_SCHEDULING] = "00;35", return _gst_info_category_strings[category];
[GST_CAT_DATAFLOW] = "00;32", else
[GST_CAT_BUFFER] = "00;32", return NULL;
[GST_CAT_CAPS] = "", }
[GST_CAT_CLOCK] = "",
[GST_CAT_ELEMENT_PADS] = "",
[GST_CAT_ELEMENTFACTORY] = "",
[GST_CAT_PADS] = "",
[GST_CAT_PIPELINE] = "",
[GST_CAT_PLUGIN_LOADING] = "00;36",
[GST_CAT_PLUGIN_ERRORS] = "05;31",
[GST_CAT_PLUGIN_INFO] = "00;36",
[GST_CAT_PROPERTIES] = "",
[GST_CAT_THREAD] = "00;31",
[GST_CAT_TYPES] = "",
[GST_CAT_XML] = "",
[GST_CAT_NEGOTIATION] = "",
[31] = "",
/*
* Attribute codes:
* 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
* Text color codes:
* 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
* Background color codes:
* 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
*/
const gchar *_gst_category_colors[32] = {
[GST_CAT_GST_INIT] = "07;37",
[GST_CAT_COTHREADS] = "00;32",
[GST_CAT_COTHREAD_SWITCH] = "00;37;42",
[GST_CAT_AUTOPLUG] = "00;34",
[GST_CAT_AUTOPLUG_ATTEMPT] = "00;36;44",
[GST_CAT_PARENTAGE] = "01;37;41", // !!
[GST_CAT_STATES] = "00;31",
[GST_CAT_PLANNING] = "07;35",
[GST_CAT_SCHEDULING] = "00;35",
[GST_CAT_DATAFLOW] = "00;32",
[GST_CAT_BUFFER] = "00;32",
[GST_CAT_CAPS] = "04;34",
[GST_CAT_CLOCK] = "00;33", // !!
[GST_CAT_ELEMENT_PADS] = "01;37;41", // !!
[GST_CAT_ELEMENTFACTORY] = "01;37;41", // !!
[GST_CAT_PADS] = "01;37;41", // !!
[GST_CAT_PIPELINE] = "01;37;41", // !!
[GST_CAT_PLUGIN_LOADING] = "00;36",
[GST_CAT_PLUGIN_ERRORS] = "05;31",
[GST_CAT_PLUGIN_INFO] = "00;36",
[GST_CAT_PROPERTIES] = "00;37;44", // !!
[GST_CAT_THREAD] = "00;31",
[GST_CAT_TYPES] = "01;37;41", // !!
[GST_CAT_XML] = "01;37;41", // !!
[GST_CAT_NEGOTIATION] = "07;34",
[GST_CAT_REFCOUNTING] = "00;34:42",
[31] = "",
}; };
/* colorization hash - DEPRACATED in favor of above */
/* colorization hash */
inline gint _gst_debug_stringhash_color(gchar *file) { inline gint _gst_debug_stringhash_color(gchar *file) {
int filecolor; int filecolor = 0;
while (file[0]) filecolor += *(char *)(file++); while (file[0]) filecolor += *(char *)(file++);
filecolor = (filecolor % 6) + 31; filecolor = (filecolor % 6) + 31;
return filecolor; return filecolor;
} }
/***** DEBUG system *****/
GstDebugHandler _gst_debug_handler = gst_default_debug_handler;
guint32 _gst_debug_categories = 0x00000000;
/**
* gst_default_debug_handler:
* @category: category of the DEBUG message
* @file: the file the DEBUG occurs in
* @function: the function the DEBUG occurs in
* @line: the line number in the file
* @debug_string: the current debug_string in the function, if any
* @element: pointer to the #GstElement in question
* @string: the actual DEBUG string
*
* Prints out the DEBUG mesage in a variant of the following form:
*
* DEBUG(pid:cid):gst_function:542(args): [elementname] something neat happened
*/
void
gst_default_debug_handler (gint category, gboolean incore, gchar *file, gchar *function,
gint line, gchar *debug_string,
void *element, gchar *string)
{
gchar *empty = "";
gchar *elementname = empty,*location = empty;
int pthread_id = getpid();
int cothread_id = cothread_getcurrent();
#ifdef GST_DEBUG_COLOR
int pthread_color = pthread_id%6 + 31;
int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
#endif
if (debug_string == NULL) debug_string = "";
// if (category != GST_CAT_GST_INIT)
location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
if (element && GST_IS_ELEMENT (element))
#ifdef GST_DEBUG_COLOR
elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
#else
elementname = g_strdup_printf (" [%s]", GST_OBJECT_NAME (element));
#endif
#ifdef GST_DEBUG_COLOR
fprintf(stderr,"DEBUG(\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
"%s;%sm%s%s\033[00m %s",
pthread_color,pthread_id,cothread_color,cothread_id,incore?"00":"01",
_gst_category_colors[category],location,elementname,string);
#else
fprintf(stderr,"DEBUG(%5d:%2d)%s%s %s",
pthread_id,cothread_id,location,elementname,string);
#endif /* GST_DEBUG_COLOR */
if (location != empty) g_free(location);
if (elementname != empty) g_free(elementname);
g_free(string);
}
/**
* gst_debug_set_categories:
* @categories: bitmask of DEBUG categories to enable
*
* Enable the output of DEBUG categories based on the given bitmask.
* The bit for any given category is (1 << GST_CAT_...).
*/
void
gst_debug_set_categories (guint32 categories) {
_gst_debug_categories = categories;
if (categories)
GST_INFO (0, "setting DEBUG categories to 0x%08X",categories);
}
/**
* gst_debug_get_categories:
*
* Returns: the current bitmask of enabled DEBUG categories
* The bit for any given category is (1 << GST_CAT_...).
*/
guint32
gst_debug_get_categories () {
return _gst_debug_categories;
}
/**
* gst_debug_enable_category:
* @category: the category to enable
*
* Enables the given GST_CAT_... DEBUG category.
*/
void
gst_debug_enable_category (gint category) {
_gst_debug_categories |= (1 << category);
if (_gst_debug_categories)
GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
}
/**
* gst_debug_disable_category:
* @category: the category to disable
*
* Disables the given GST_CAT_... DEBUG category.
*/
void
gst_debug_disable_category (gint category) {
_gst_debug_categories &= ~ (1 << category);
if (_gst_debug_categories)
GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
}
/***** INFO system *****/
GstInfoHandler _gst_info_handler = gst_default_info_handler;
#ifdef GST_INFO_ENABLED_VERBOSE
guint32 _gst_info_categories = 0xffffffff;
#else
guint32 _gst_info_categories = 0x00000001;
#endif
/** /**
* gst_default_info_handler: * gst_default_info_handler:
* @category: category of the INFO message * @category: category of the INFO message
@ -123,12 +259,18 @@ inline gint _gst_debug_stringhash_color(gchar *file) {
* INFO:gst_function:542(args): [elementname] something neat happened * INFO:gst_function:542(args): [elementname] something neat happened
*/ */
void void
gst_default_info_handler (gint category, gchar *file, gchar *function, gst_default_info_handler (gint category, gboolean incore,gchar *file, gchar *function,
gint line, gchar *debug_string, gint line, gchar *debug_string,
void *element, gchar *string) void *element, gchar *string)
{ {
gchar *empty = ""; gchar *empty = "";
gchar *elementname = empty,*location = empty; gchar *elementname = empty,*location = empty;
int pthread_id = getpid();
int cothread_id = cothread_getcurrent();
#ifdef GST_DEBUG_COLOR
int pthread_color = pthread_id%6 + 31;
int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
#endif
if (debug_string == NULL) debug_string = ""; if (debug_string == NULL) debug_string = "";
if (category != GST_CAT_GST_INIT) if (category != GST_CAT_GST_INIT)
@ -138,15 +280,17 @@ gst_default_info_handler (gint category, gchar *file, gchar *function,
#ifdef GST_DEBUG_ENABLED #ifdef GST_DEBUG_ENABLED
#ifdef GST_DEBUG_COLOR #ifdef GST_DEBUG_COLOR
fprintf(stderr,"INFO(%d:%d):\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n", fprintf(stderr,"\033[01mINFO\033[00m (\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
getpid(),cothread_getcurrent(),_gst_category_colors[category],location,elementname,string); GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
pthread_color,pthread_id,cothread_color,cothread_id,
_gst_category_colors[category],location,elementname,string);
#else #else
fprintf(stderr,"INFO(%d:%d):%s%s %s\n", fprintf(stderr,"INFO (%5d:%2d)%s%s %s\n",
getpid(),cothread_getcurrent(),location,elementname,string); pthread_id,cothread_id,location,elementname,string);
#endif /* GST_DEBUG_COLOR */ #endif /* GST_DEBUG_COLOR */
#else #else
#ifdef GST_DEBUG_COLOR #ifdef GST_DEBUG_COLOR
fprintf(stderr,"INFO:\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n", fprintf(stderr,"\033[01mINFO\033[00m:\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
location,elementname,_gst_category_colors[category],string); location,elementname,_gst_category_colors[category],string);
#else #else
fprintf(stderr,"INFO:%s%s %s\n", fprintf(stderr,"INFO:%s%s %s\n",
@ -213,77 +357,6 @@ gst_info_disable_category (gint category) {
/***** DEBUG system *****/
guint32 _gst_debug_categories = 0x00000000;
/**
* gst_debug_set_categories:
* @categories: bitmask of DEBUG categories to enable
*
* Enable the output of DEBUG categories based on the given bitmask.
* The bit for any given category is (1 << GST_CAT_...).
*/
void
gst_debug_set_categories (guint32 categories) {
_gst_debug_categories = categories;
if (categories)
GST_INFO (0, "setting DEBUG categories to 0x%08X",categories);
}
/**
* gst_debug_get_categories:
*
* Returns: the current bitmask of enabled DEBUG categories
* The bit for any given category is (1 << GST_CAT_...).
*/
guint32
gst_debug_get_categories () {
return _gst_debug_categories;
}
/**
* gst_debug_enable_category:
* @category: the category to enable
*
* Enables the given GST_CAT_... DEBUG category.
*/
void
gst_debug_enable_category (gint category) {
_gst_debug_categories |= (1 << category);
if (_gst_debug_categories)
GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
}
/**
* gst_debug_disable_category:
* @category: the category to disable
*
* Disables the given GST_CAT_... DEBUG category.
*/
void
gst_debug_disable_category (gint category) {
_gst_debug_categories &= ~ (1 << category);
if (_gst_debug_categories)
GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
}
/**
* gst_get_category_name:
* @category: the category to return the name of
*
* Returns: string containing the name of the category
*/
const gchar *
gst_get_category_name (gint category) {
if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
return _gst_info_category_strings[category];
else
return NULL;
}
/***** ERROR system *****/ /***** ERROR system *****/
GstErrorHandler _gst_error_handler = gst_default_error_handler; GstErrorHandler _gst_error_handler = gst_default_error_handler;
@ -364,3 +437,24 @@ gst_default_error_handler (gchar *file, gchar *function,
exit(1); exit(1);
} }
/***** DEBUG system *****/
GHashTable *__gst_function_pointers = NULL;
gchar *
_gst_debug_nameof_funcptr (void *ptr)
{
gchar *ptrname;
Dl_info dlinfo;
if (__gst_function_pointers) {
if ((ptrname = g_hash_table_lookup(__gst_function_pointers,ptr)))
return g_strdup(ptrname);
} else if (dladdr(ptr,&dlinfo) && dlinfo.dli_sname) {
return g_strdup(dlinfo.dli_sname);
} else {
return g_strdup_printf("%p",ptr);
}
return NULL;
}

View file

@ -34,6 +34,14 @@
#include "cothreads.h" #include "cothreads.h"
/***** are we in the core or not? *****/
#ifdef __GST_PRIVATE_H__
#define _GST_DEBUG_INCORE TRUE
#else
#define _GST_DEBUG_INCORE FALSE
#endif
/* colorization stuff */ /* colorization stuff */
#ifdef GST_DEBUG_COLOR #ifdef GST_DEBUG_COLOR
#ifdef __GST_PRIVATE_H__ /* FIXME this should be some libgst.la -specific thing */ #ifdef __GST_PRIVATE_H__ /* FIXME this should be some libgst.la -specific thing */
@ -47,13 +55,51 @@ gint _gst_debug_stringhash_color(gchar *file);
/**********************************************************************
* Categories
**********************************************************************/
const gchar * gst_get_category_name (gint category);
enum {
GST_CAT_GST_INIT = 0, // Library initialization
GST_CAT_COTHREADS, // Cothread creation, etc.
GST_CAT_COTHREAD_SWITCH, // Cothread switching
GST_CAT_AUTOPLUG, // Successful autoplug results
GST_CAT_AUTOPLUG_ATTEMPT, // Attempted autoplug operations
GST_CAT_PARENTAGE, // GstBin parentage issues
GST_CAT_STATES, // State changes and such
GST_CAT_PLANNING, // Plan generation
GST_CAT_SCHEDULING, // Schedule construction
GST_CAT_DATAFLOW, // Events during actual data movement
GST_CAT_BUFFER, // Buffer creation/destruction
GST_CAT_CAPS, // Capabilities matching
GST_CAT_CLOCK, // Clocking
GST_CAT_ELEMENT_PADS, // Element pad management
GST_CAT_ELEMENTFACTORY, // Elementfactory stuff
GST_CAT_PADS, // Pad creation/connection
GST_CAT_PIPELINE, // Pipeline stuff
GST_CAT_PLUGIN_LOADING, // Plugin loading
GST_CAT_PLUGIN_ERRORS, // Errors during plugin loading
GST_CAT_PLUGIN_INFO, // Plugin state information
GST_CAT_PROPERTIES, // Properties
GST_CAT_THREAD, // Thread creation/management
GST_CAT_TYPES, // Typing
GST_CAT_XML, // XML load/save of everything
GST_CAT_NEGOTIATION, // Caps Negotiation stuff
GST_CAT_REFCOUNTING, // Ref Counting stuff
GST_CAT_MAX_CATEGORY = 31
};
extern const gchar *_gst_category_colors[32];
/********************************************************************** /**********************************************************************
* DEBUG system * DEBUG system
**********************************************************************/ **********************************************************************/
extern guint32 _gst_debug_categories;
/* for include files that make too much noise normally */ /* for include files that make too much noise normally */
#ifdef GST_DEBUG_FORCE_DISABLE #ifdef GST_DEBUG_FORCE_DISABLE
#undef GST_DEBUG_ENABLED #undef GST_DEBUG_ENABLED
@ -69,109 +115,69 @@ extern guint32 _gst_debug_categories;
//#define GST_DEBUG_ENABLE_CATEGORIES 0x00000000 //#define GST_DEBUG_ENABLE_CATEGORIES 0x00000000
//#endif //#endif
typedef void (*GstDebugHandler) (gint category,gboolean core,gchar *file,gchar *function,
gint line,gchar *debug_string,
void *element,gchar *string);
void gst_default_debug_handler (gint category,gboolean incore,gchar *file,gchar *function,
gint line,gchar *debug_string,
void *element,gchar *string);
extern guint32 _gst_debug_categories;
extern GstDebugHandler _gst_debug_handler;
/* fallback, this should probably be a 'weak' symbol or something */ /* fallback, this should probably be a 'weak' symbol or something */
G_GNUC_UNUSED static gchar *_debug_string = NULL; G_GNUC_UNUSED static gchar *_debug_string = NULL;
#ifdef GST_DEBUG_COLOR
#ifdef _GST_COLOR_CODE
#warning have a coded debug
#define GST_DEBUG_PREFIX(cat,format,args...) \
"DEBUG(%d:%d)\033[" _GST_COLOR_CODE "m" __PRETTY_FUNCTION__ ":%d\033[00m" format , \
getpid() , cothread_getcurrent() , __LINE__ , ## args
#else
#define GST_DEBUG_PREFIX(cat,format,args...) \
"DEBUG(%d:%d)\033[" GST_DEBUG_CHAR_MODE ";%sm" __PRETTY_FUNCTION__ ":%d\033[00m" format , \
getpid() , cothread_getcurrent() , _gst_category_colors[cat] , __LINE__ , ## args
#endif /* _GST_COLOR_CODE */
#else
#define GST_DEBUG_PREFIX(cat,format,args...) \
"DEBUG(%d:%d)" __PRETTY_FUNCTION__ ":%d" format , getpid() ,cothread_getcurrent() , __LINE__ , ## args
#endif
#ifdef GST_DEBUG_ENABLED #ifdef GST_DEBUG_ENABLED
#define GST_DEBUG(cat,format,args...) G_STMT_START{ \ #define GST_DEBUG(cat,format,args...) G_STMT_START{ \
if (((1<<cat) & GST_DEBUG_ENABLE_CATEGORIES) && \ if ((1<<cat) & _gst_debug_categories) \
((1<<cat) & _gst_debug_categories)) \ _gst_debug_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
(_debug_string != NULL) ? \ NULL,g_strdup_printf( format , ## args )); \
fprintf(stderr,GST_DEBUG_PREFIX(cat,"%s: "format , _debug_string , ## args )) : \
fprintf(stderr,GST_DEBUG_PREFIX(cat,": "format , ## args )); \
}G_STMT_END }G_STMT_END
#define GST_DEBUG_NOPREFIX(cat,format,args...) G_STMT_START{ \ #define GST_DEBUG_ELEMENT(cat,element,format,args...) G_STMT_START{ \
if (((1<<cat) & GST_DEBUG_ENABLE_CATEGORIES) && \ if ((1<<cat) & _gst_debug_categories) \
((1<<cat) & _gst_debug_categories)) \ _gst_debug_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
fprintf(stderr,format , ## args ); \ element,g_strdup_printf( format , ## args )); \
}G_STMT_END }G_STMT_END
#define GST_DEBUG_ENTER(format, args...) G_STMT_START{ \
if (((1<<31) & GST_DEBUG_ENABLE_CATEGORIES) && \
((1<<31) & _gst_debug_categories)) \
fprintf(stderr,GST_DEBUG_PREFIX(31,format": entering\n" , ## args )); \
}G_STMT_END
// FIXME FIXME FIXME this leaks like crazy
#define GST_DEBUG_SET_STRING(format, args...) \
gchar *_debug_string = g_strdup_printf(format , ## args )
#define GST_DEBUG_ENTER_STRING GST_DEBUG_ENTER("%s",_debug_string)
#define GST_DEBUG_LEAVE(format, args...) G_STMT_START{ \
if (((1<<31) & GST_DEBUG_ENABLE_CATEGORIES) && \
((1<<31) & _gst_debug_categories)) \
if (_debug_string != NULL) g_free(_debug_string),\
fprintf(stderr,GST_DEBUG_PREFIX(31,format": leaving\n" , ## args )); \
}G_STMT_END
#define GST_DEBUG_LEAVE_STRING GST_DEBUG_LEAVE("%s",_debug_string)
#else #else
#define GST_DEBUG(format, args...) #define GST_DEBUG(cat,format,args...)
#define GST_DEBUG_NOPREFIX(format, args...) #define GST_DEBUG_ELEMENT(cat,element,format,args...)
#define GST_DEBUG_ENTER(format, args...)
#define GST_DEBUG_LEAVE(format, args...)
#define GST_DEBUG_SET_STRING(format, args...)
#define GST_DEBUG_ENTER_STRING
#endif #endif
/********** some convenience macros for debugging **********/ /********** some convenience macros for debugging **********/
#define GST_DEBUG_PAD_NAME(pad) \ #define GST_DEBUG_PAD_NAME(pad) \
(GST_OBJECT_PARENT(pad) != NULL) ? \ (GST_OBJECT_PARENT(pad) != NULL) ? \
GST_OBJECT_NAME (GST_OBJECT_PARENT(pad)) : \ GST_OBJECT_NAME (GST_OBJECT_PARENT(pad)) : \
"''", GST_OBJECT_NAME (pad) "''", GST_OBJECT_NAME (pad)
#ifdef GST_DEBUG_COLOR
#define GST_DEBUG_ENTER(format, args...) GST_DEBUG( 31 , format ": \033[01;37mentering\033[00m\n" , ##args )
/********** function pointer stuff **********/ #define GST_DEBUG_LEAVE(format, args...) GST_DEBUG( 31 , format ": \033[01;37mleaving\033[00m\n" , ##args )
extern GHashTable *__gst_function_pointers;
#ifdef GST_DEBUG_ENABLED
#define GST_DEBUG_FUNCPTR(ptr) _gst_debug_register_funcptr((void *)(ptr), #ptr)
#define GST_DEBUG_FUNCPTR_NAME(ptr) _gst_debug_nameof_funcptr((void *)ptr)
#else #else
#define GST_DEBUG_FUNCPTR(ptr) (ptr) #define GST_DEBUG_ENTER(format, args...) GST_DEBUG( 31 , format ": entering\n" , ##args )
#define GST_DEBUG_FUNCPTR_NAME(ptr) "" #define GST_DEBUG_LEAVE(format, args...) GST_DEBUG( 31 , format ": leaving\n" , ##args )
#endif #endif
static inline void *
_gst_debug_register_funcptr (void *ptr, gchar *ptrname)
{
if (!__gst_function_pointers) __gst_function_pointers = g_hash_table_new(g_direct_hash,g_direct_equal);
if (!g_hash_table_lookup(__gst_function_pointers,ptr))
g_hash_table_insert(__gst_function_pointers,ptr,ptrname);
return ptr;
}
static inline gchar * /***** Colorized debug for thread ids *****/
_gst_debug_nameof_funcptr (void *ptr) #ifdef GST_DEBUG_COLOR
{ #define GST_DEBUG_THREAD_FORMAT "\033[00;%dm%d\033[00m"
gchar *ptrname = (gchar*)( __gst_function_pointers ? g_hash_table_lookup(__gst_function_pointers,ptr) : NULL ); #define GST_DEBUG_THREAD_ARGS(id) ( ((id) < 0) ? 37 : ((id) % 6 + 31) ), (id)
// FIXME this must go away, it's a major leak #else
if (!ptrname) return g_strdup_printf("%p",ptr); #define GST_DEBUG_THREAD_FORMAT "%d"
else return ptrname; #define GST_DEBUG_THREAD_ARGS(id) (id)
} #endif
/********************************************************************** /**********************************************************************
@ -227,11 +233,11 @@ G_GNUC_UNUSED static GModule *_debug_self_module = NULL;
* INFO system * INFO system
**********************************************************************/ **********************************************************************/
typedef void (*GstInfoHandler) (gint category,gchar *file,gchar *function, typedef void (*GstInfoHandler) (gint category,gboolean incore,gchar *file,gchar *function,
gint line,gchar *debug_string, gint line,gchar *debug_string,
void *element,gchar *string); void *element,gchar *string);
void gst_default_info_handler (gint category,gchar *file,gchar *function, void gst_default_info_handler (gint category,gboolean incore,gchar *file,gchar *function,
gint line,gchar *debug_string, gint line,gchar *debug_string,
void *element,gchar *string); void *element,gchar *string);
@ -250,13 +256,13 @@ extern guint32 _gst_info_categories;
#ifdef GST_INFO_ENABLED #ifdef GST_INFO_ENABLED
#define GST_INFO(cat,format,args...) G_STMT_START{ \ #define GST_INFO(cat,format,args...) G_STMT_START{ \
if ((1<<cat) & _gst_info_categories) \ if ((1<<cat) & _gst_info_categories) \
_gst_info_handler(cat,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \ _gst_info_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
NULL,g_strdup_printf( format , ## args )); \ NULL,g_strdup_printf( format , ## args )); \
}G_STMT_END }G_STMT_END
#define GST_INFO_ELEMENT(cat,element,format,args...) G_STMT_START{ \ #define GST_INFO_ELEMENT(cat,element,format,args...) G_STMT_START{ \
if ((1<<cat) & _gst_info_categories) \ if ((1<<cat) & _gst_info_categories) \
_gst_info_handler(cat,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \ _gst_info_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
element,g_strdup_printf( format , ## args )); \ element,g_strdup_printf( format , ## args )); \
}G_STMT_END }G_STMT_END
@ -276,42 +282,6 @@ guint32 gst_debug_get_categories (void);
void gst_debug_enable_category (gint category); void gst_debug_enable_category (gint category);
void gst_debug_disable_category (gint category); void gst_debug_disable_category (gint category);
const gchar * gst_get_category_name (gint category);
enum {
GST_CAT_GST_INIT = 0, // Library initialization
GST_CAT_COTHREADS, // Cothread creation, etc.
GST_CAT_COTHREAD_SWITCH, // Cothread switching
GST_CAT_AUTOPLUG, // Successful autoplug results
GST_CAT_AUTOPLUG_ATTEMPT, // Attempted autoplug operations
GST_CAT_PARENTAGE, // GstBin parentage issues
GST_CAT_STATES, // State changes and such
GST_CAT_PLANNING, // Plan generation
GST_CAT_SCHEDULING, // Schedule construction
GST_CAT_DATAFLOW, // Events during actual data movement
GST_CAT_BUFFER, // Buffer creation/destruction
GST_CAT_CAPS, // Capabilities matching
GST_CAT_CLOCK, // Clocking
GST_CAT_ELEMENT_PADS, // Element pad management
GST_CAT_ELEMENTFACTORY, // Elementfactory stuff
GST_CAT_PADS, // Pad creation/connection
GST_CAT_PIPELINE, // Pipeline stuff
GST_CAT_PLUGIN_LOADING, // Plugin loading
GST_CAT_PLUGIN_ERRORS, // Errors during plugin loading
GST_CAT_PLUGIN_INFO, // Plugin state information
GST_CAT_PROPERTIES, // Properties
GST_CAT_THREAD, // Thread creation/management
GST_CAT_TYPES, // Typing
GST_CAT_XML, // XML load/save of everything
GST_CAT_NEGOTIATION, // Caps Negotiation stuff
GST_CAT_MAX_CATEGORY,
};
extern const gchar *_gst_category_colors[GST_CAT_MAX_CATEGORY];
@ -339,4 +309,30 @@ extern GstErrorHandler _gst_error_handler;
/********** function pointer stuff **********/
extern GHashTable *__gst_function_pointers;
#if GST_DEBUG_ENABLED
#define GST_DEBUG_FUNCPTR(ptr) _gst_debug_register_funcptr((void *)(ptr), #ptr)
#define GST_DEBUG_FUNCPTR_NAME(ptr) _gst_debug_nameof_funcptr((void *)ptr)
#else
#define GST_DEBUG_FUNCPTR(ptr) (ptr)
#define GST_DEBUG_FUNCPTR_NAME(ptr) ""
#endif
static inline void *
_gst_debug_register_funcptr (void *ptr, gchar *ptrname)
{
if (!__gst_function_pointers) __gst_function_pointers = g_hash_table_new(g_direct_hash,g_direct_equal);
if (!g_hash_table_lookup(__gst_function_pointers,ptr))
g_hash_table_insert(__gst_function_pointers,ptr,ptrname);
return ptr;
}
gchar *_gst_debug_nameof_funcptr (void *ptr);
#endif /* __GSTINFO_H__ */ #endif /* __GSTINFO_H__ */

View file

@ -53,6 +53,10 @@ static guint gst_signal_object_signals[SO_LAST_SIGNAL] = { 0 };
static void gst_object_class_init (GstObjectClass *klass); static void gst_object_class_init (GstObjectClass *klass);
static void gst_object_init (GstObject *object); static void gst_object_init (GstObject *object);
static void gst_object_real_destroy (GtkObject *gtk_object);
static void gst_object_shutdown (GtkObject *gtk_object);
static void gst_object_finalize (GtkObject *gtk_object);
static GtkObjectClass *parent_class = NULL; static GtkObjectClass *parent_class = NULL;
static guint gst_object_signals[LAST_SIGNAL] = { 0 }; static guint gst_object_signals[LAST_SIGNAL] = { 0 };
@ -105,6 +109,10 @@ gst_object_class_init (GstObjectClass *klass)
klass->path_string_separator = "/"; klass->path_string_separator = "/";
klass->signal_object = gtk_type_new (gst_signal_object_get_type ()); klass->signal_object = gtk_type_new (gst_signal_object_get_type ());
gtkobject_class->shutdown = gst_object_shutdown;
gtkobject_class->destroy = gst_object_real_destroy;
gtkobject_class->finalize = gst_object_finalize;
} }
static void static void
@ -118,9 +126,12 @@ gst_object_init (GstObject *object)
#ifdef HAVE_ATOMIC_H #ifdef HAVE_ATOMIC_H
atomic_set(&(object->refcount),1); atomic_set(&(object->refcount),1);
#else #else
object->refcount++; object->refcount = 1;
#endif #endif
object->parent = NULL; object->parent = NULL;
object->flags = 0;
GST_FLAG_SET (object, GST_FLOATING);
} }
/** /**
@ -136,6 +147,122 @@ gst_object_new (void)
return GST_OBJECT (gtk_type_new (gst_object_get_type ())); return GST_OBJECT (gtk_type_new (gst_object_get_type ()));
} }
/**
* gst_object_ref:
* @object: GstObject to reference
*
* Increments the refence count on the object.
*/
GstObject*
gst_object_ref (GstObject *object)
{
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
GST_DEBUG (GST_CAT_REFCOUNTING, "ref '%s' %d->%d\n",GST_OBJECT_NAME(object),
GTK_OBJECT(object)->ref_count,GTK_OBJECT(object)->ref_count+1);
gtk_object_ref (GTK_OBJECT (object));
return object;
}
#define gst_object_ref gst_object_ref
/**
* gst_object_unref:
* @object: GstObject to unreference
*
* Decrements the refence count on the object. If reference count hits
* zero, destroy the object.
*/
void
gst_object_unref (GstObject *object)
{
g_return_if_fail (GST_IS_OBJECT (object));
GST_DEBUG (GST_CAT_REFCOUNTING, "unref '%s' %d->%d\n",GST_OBJECT_NAME(object),
GTK_OBJECT(object)->ref_count,GTK_OBJECT(object)->ref_count-1);
gtk_object_unref (GTK_OBJECT (object));
}
#define gst_object_unref gst_object_unref
/**
* gst_object_sink:
* @object: GstObject to sink
*
* Removes floating reference on an object. Any newly created object has
* a refcount of 1 and is FLOATING. This function should be used when
* creating a new object to symbolically 'take ownership of' the object.
*/
void
gst_object_sink (GstObject *object)
{
g_return_if_fail (object != NULL);
g_return_if_fail (GST_IS_OBJECT (object));
GST_DEBUG (GST_CAT_REFCOUNTING, "sink '%s'\n",GST_OBJECT_NAME(object));
if (GST_OBJECT_FLOATING (object))
{
GST_FLAG_UNSET (object, GST_FLOATING);
gst_object_unref (object);
}
}
void
gst_object_destroy (GstObject *object)
{
g_return_if_fail (object != NULL);
g_return_if_fail (GST_IS_OBJECT (object));
GST_DEBUG (GST_CAT_REFCOUNTING, "destroy '%s'\n",GST_OBJECT_NAME(object));
if (!GST_OBJECT_DESTROYED (object))
{
/* need to hold a reference count around all class method
* invocations.
*/
gst_object_ref (object);
GTK_OBJECT (object)->klass->shutdown (GTK_OBJECT (object));
gst_object_unref (object);
}
}
static void
gst_object_shutdown (GtkObject *object)
{
GST_DEBUG (GST_CAT_REFCOUNTING, "shutdown '%s'\n",GST_OBJECT_NAME(object));
GST_FLAG_SET (GST_OBJECT (object), GST_DESTROYED);
parent_class->shutdown (GTK_OBJECT (object));
}
/* finilize is called when the object has to free its resources */
static void
gst_object_real_destroy (GtkObject *gtk_object)
{
GST_DEBUG (GST_CAT_REFCOUNTING, "destroy '%s'\n",GST_OBJECT_NAME(gtk_object));
GST_OBJECT_PARENT (gtk_object) = NULL;
parent_class->destroy (gtk_object);
}
/* finilize is called when the object has to free its resources */
static void
gst_object_finalize (GtkObject *gtk_object)
{
GstObject *object;
object = GST_OBJECT (gtk_object);
GST_DEBUG (GST_CAT_REFCOUNTING, "finalize '%s'\n",GST_OBJECT_NAME(object));
if (object->name != NULL)
g_free (object->name);
g_mutex_free (object->lock);
parent_class->finalize (gtk_object);
}
/** /**
* gst_object_set_name: * gst_object_set_name:
* @object: GstObject to set the name of * @object: GstObject to set the name of
@ -315,26 +442,31 @@ gst_object_unref (GstObject *object)
#endif /* gst_object_unref */ #endif /* gst_object_unref */
/** /**
* gst_object_sink: * gst_object_check_uniqueness:
* @object: GstObject to sink * @list: a list of #GstObject to check through
* @name: the name to search for
* *
* Removes floating reference on an object. Any newly created object has * This function checks through the list of objects to see if the name
* a refcount of 1 and is FLOATING. This function should be used when * given appears in the list as the name of an object. It returns TRUE if
* creating a new object to symbolically 'take ownership of' the object. * the name does not exist in the list.
*
* Returns: TRUE if the name doesn't appear in the list, FALSE if it does.
*/ */
#ifndef gst_object_sink gboolean
void gst_object_check_uniqueness (GList *list, const gchar *name)
gst_object_sink (GstObject *object)
{ {
g_return_if_fail (object != NULL); GstObject *child;
g_return_if_fail (GST_IS_OBJECT (object));
if (GTK_OBJECT_FLOATING (object)) { while (list) {
GTK_OBJECT_UNSET_FLAGS (object, GTK_FLOATING); child = GST_OBJECT (list->data);
gst_object_unref (object); list = g_list_next(list);
if (strcmp(GST_OBJECT_NAME(child), name) == 0) return FALSE;
} }
return TRUE;
} }
#endif /* gst_object_sink */
/** /**
* gst_object_save_thyself: * gst_object_save_thyself:
@ -528,6 +660,3 @@ gst_class_signal_emit_by_name (GstObject *object,
gtk_signal_emit_by_name (oclass->signal_object, name, object, self); gtk_signal_emit_by_name (oclass->signal_object, name, object, self);
} }

View file

@ -28,6 +28,8 @@
#include <gst/gsttrace.h> #include <gst/gsttrace.h>
#include <parser.h> #include <parser.h>
#include <gst/gsttypes.h>
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
@ -55,10 +57,16 @@ extern "C" {
#define GST_IS_OBJECT_CLASS(obj) \ #define GST_IS_OBJECT_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_OBJECT)) (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_OBJECT))
typedef struct _GstObject GstObject; //typedef struct _GstObject GstObject;
typedef struct _GstObjectClass GstObjectClass; //typedef struct _GstObjectClass GstObjectClass;
//
typedef enum
{
GST_DESTROYED = 0,
GST_FLOATING,
#define GST_OBJECT_FLAG_LAST 4 GST_OBJECT_FLAG_LAST = 4,
} GstObjectFlags;
struct _GstObject { struct _GstObject {
GtkObject object; GtkObject object;
@ -76,6 +84,8 @@ struct _GstObject {
/* this objects parent */ /* this objects parent */
GstObject *parent; GstObject *parent;
guint32 flags;
}; };
struct _GstObjectClass { struct _GstObjectClass {
@ -89,19 +99,23 @@ struct _GstObjectClass {
void (*object_saved) (GstObject *object, xmlNodePtr parent); void (*object_saved) (GstObject *object, xmlNodePtr parent);
/* functions go here */ /* functions go here */
void (*destroy) (GstObject *object);
xmlNodePtr (*save_thyself) (GstObject *object, xmlNodePtr parent); xmlNodePtr (*save_thyself) (GstObject *object, xmlNodePtr parent);
void (*restore_thyself) (GstObject *object, xmlNodePtr self); void (*restore_thyself) (GstObject *object, xmlNodePtr self);
}; };
#define GST_OBJECT_NAME(obj) (const gchar*)(((GstObject *)(obj))->name) #define GST_FLAGS(obj) (GST_OBJECT (obj)->flags)
#define GST_OBJECT_PARENT(obj) (((GstObject *)(obj))->parent)
#define GST_FLAGS(obj) GTK_OBJECT_FLAGS(obj)
#define GST_FLAG_IS_SET(obj,flag) (GST_FLAGS (obj) & (1<<(flag))) #define GST_FLAG_IS_SET(obj,flag) (GST_FLAGS (obj) & (1<<(flag)))
#define GST_FLAG_SET(obj,flag) G_STMT_START{ (GST_FLAGS (obj) |= (1<<(flag))); }G_STMT_END #define GST_FLAG_SET(obj,flag) G_STMT_START{ (GST_FLAGS (obj) |= (1<<(flag))); }G_STMT_END
#define GST_FLAG_UNSET(obj,flag) G_STMT_START{ (GST_FLAGS (obj) &= ~(1<<(flag))); }G_STMT_END #define GST_FLAG_UNSET(obj,flag) G_STMT_START{ (GST_FLAGS (obj) &= ~(1<<(flag))); }G_STMT_END
#define GST_OBJECT_NAME(obj) (const gchar*)(((GstObject *)(obj))->name)
#define GST_OBJECT_PARENT(obj) (((GstObject *)(obj))->parent)
#define GST_OBJECT_DESTROYED(obj) (GST_FLAG_IS_SET (obj, GST_DESTROYED))
#define GST_OBJECT_FLOATING(obj) (GST_FLAG_IS_SET (obj, GST_FLOATING))
/* object locking */ /* object locking */
#define GST_LOCK(obj) (g_mutex_lock(GST_OBJECT(obj)->lock)) #define GST_LOCK(obj) (g_mutex_lock(GST_OBJECT(obj)->lock))
#define GST_TRYLOCK(obj) (g_mutex_trylock(GST_OBJECT(obj)->lock)) #define GST_TRYLOCK(obj) (g_mutex_trylock(GST_OBJECT(obj)->lock))
@ -122,15 +136,17 @@ void gst_object_set_parent (GstObject *object,GstObject *parent);
GstObject* gst_object_get_parent (GstObject *object); GstObject* gst_object_get_parent (GstObject *object);
void gst_object_unparent (GstObject *object); void gst_object_unparent (GstObject *object);
gboolean gst_object_check_uniqueness (GList *list, const gchar *name);
xmlNodePtr gst_object_save_thyself (GstObject *object, xmlNodePtr parent); xmlNodePtr gst_object_save_thyself (GstObject *object, xmlNodePtr parent);
/* refcounting */ /* refcounting */
#define gst_object_ref(object) gtk_object_ref(GTK_OBJECT(object)); GstObject * gst_object_ref (GstObject *object);
#define gst_object_unref(object) gtk_object_unref(GTK_OBJECT(object)); void gst_object_unref (GstObject *object);
#define gst_object_sink(object) gtk_object_sink(GTK_OBJECT(object)); void gst_object_sink (GstObject *object);
/* destroying an object */ /* destroying an object */
#define gst_object_destroy(object) gtk_object_destroy(GTK_OBJECT(object)) void gst_object_destroy (GstObject *object);
/* printing out the 'path' of the object */ /* printing out the 'path' of the object */
gchar * gst_object_get_path_string (GstObject *object); gchar * gst_object_get_path_string (GstObject *object);

View file

@ -27,6 +27,7 @@
#include "gstelement.h" #include "gstelement.h"
#include "gsttype.h" #include "gsttype.h"
#include "gstbin.h" #include "gstbin.h"
#include "gstscheduler.h"
/***** Start with the base GstPad class *****/ /***** Start with the base GstPad class *****/
@ -78,6 +79,9 @@ gst_pad_init (GstPad *pad)
enum { enum {
REAL_SET_ACTIVE, REAL_SET_ACTIVE,
REAL_CAPS_CHANGED, REAL_CAPS_CHANGED,
REAL_CAPS_NEGO_FAILED,
REAL_CONNECTED,
REAL_DISCONNECTED,
/* FILL ME */ /* FILL ME */
REAL_LAST_SIGNAL REAL_LAST_SIGNAL
}; };
@ -97,7 +101,6 @@ static void gst_real_pad_get_arg (GtkObject *object,GtkArg *arg,guint id);
static void gst_real_pad_destroy (GtkObject *object); static void gst_real_pad_destroy (GtkObject *object);
static void gst_pad_push_func (GstPad *pad, GstBuffer *buf); static void gst_pad_push_func (GstPad *pad, GstBuffer *buf);
static gboolean gst_pad_eos_func (GstPad *pad);
static GstPad *real_pad_parent_class = NULL; static GstPad *real_pad_parent_class = NULL;
@ -144,16 +147,31 @@ gst_real_pad_class_init (GstRealPadClass *klass)
GTK_SIGNAL_OFFSET (GstRealPadClass, caps_changed), GTK_SIGNAL_OFFSET (GstRealPadClass, caps_changed),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GTK_TYPE_POINTER); GTK_TYPE_POINTER);
gst_real_pad_signals[REAL_CAPS_NEGO_FAILED] =
gtk_signal_new ("caps_nego_failed", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstRealPadClass, caps_nego_failed),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GTK_TYPE_POINTER);
gst_real_pad_signals[REAL_CONNECTED] =
gtk_signal_new ("connected", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstRealPadClass, connected),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GTK_TYPE_POINTER);
gst_real_pad_signals[REAL_DISCONNECTED] =
gtk_signal_new ("disconnected", GTK_RUN_LAST, gtkobject_class->type,
GTK_SIGNAL_OFFSET (GstRealPadClass, disconnected),
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
GTK_TYPE_POINTER);
gtk_object_class_add_signals (gtkobject_class, gst_real_pad_signals, REAL_LAST_SIGNAL); gtk_object_class_add_signals (gtkobject_class, gst_real_pad_signals, REAL_LAST_SIGNAL);
gtk_object_add_arg_type ("GstRealPad::active", GTK_TYPE_BOOL, gtk_object_add_arg_type ("GstRealPad::active", GTK_TYPE_BOOL,
GTK_ARG_READWRITE, REAL_ARG_ACTIVE); GTK_ARG_READWRITE, REAL_ARG_ACTIVE);
gtkobject_class->destroy = gst_real_pad_destroy; gtkobject_class->destroy = GST_DEBUG_FUNCPTR(gst_real_pad_destroy);
gtkobject_class->set_arg = gst_real_pad_set_arg; gtkobject_class->set_arg = GST_DEBUG_FUNCPTR(gst_real_pad_set_arg);
gtkobject_class->get_arg = gst_real_pad_get_arg; gtkobject_class->get_arg = GST_DEBUG_FUNCPTR(gst_real_pad_get_arg);
gstobject_class->save_thyself = gst_pad_save_thyself; gstobject_class->save_thyself = GST_DEBUG_FUNCPTR(gst_pad_save_thyself);
gstobject_class->path_string_separator = "."; gstobject_class->path_string_separator = ".";
} }
@ -167,7 +185,7 @@ gst_real_pad_init (GstRealPad *pad)
pad->getfunc = NULL; pad->getfunc = NULL;
pad->getregionfunc = NULL; pad->getregionfunc = NULL;
pad->qosfunc = NULL; pad->qosfunc = NULL;
pad->eosfunc = gst_pad_eos_func; pad->eosfunc = GST_DEBUG_FUNCPTR(gst_pad_eos_func);
pad->pushfunc = GST_DEBUG_FUNCPTR(gst_pad_push_func); pad->pushfunc = GST_DEBUG_FUNCPTR(gst_pad_push_func);
pad->pullfunc = NULL; pad->pullfunc = NULL;
@ -260,6 +278,8 @@ gst_pad_new_from_template (GstPadTemplate *templ,
g_return_val_if_fail (templ != NULL, NULL); g_return_val_if_fail (templ != NULL, NULL);
pad = gst_pad_new (name, templ->direction); pad = gst_pad_new (name, templ->direction);
gst_object_ref (GST_OBJECT (templ));
gst_object_sink (GST_OBJECT (templ));
GST_PAD_PADTEMPLATE(pad) = templ; GST_PAD_PADTEMPLATE(pad) = templ;
return pad; return pad;
@ -330,8 +350,8 @@ void gst_pad_set_chain_function (GstPad *pad,
g_return_if_fail (GST_IS_REAL_PAD (pad)); g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_CHAINFUNC(pad) = chain; GST_RPAD_CHAINFUNC(pad) = chain;
GST_DEBUG (0,"chainfunc for %s:%s(@%p) at %p is set to %p\n", GST_DEBUG (GST_CAT_PADS,"chainfunc for %s:%s set to %s\n",
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_CHAINFUNC(pad),chain); GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(chain));
} }
/** /**
@ -349,8 +369,8 @@ gst_pad_set_get_function (GstPad *pad,
g_return_if_fail (GST_IS_REAL_PAD (pad)); g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_GETFUNC(pad) = get; GST_RPAD_GETFUNC(pad) = get;
GST_DEBUG (0,"getfunc for %s:%s(@%p) at %p is set to %p\n", GST_DEBUG (GST_CAT_PADS,"getfunc for %s:%s set to %s\n",
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_GETFUNC(pad),get); GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(get));
} }
/** /**
@ -368,8 +388,8 @@ gst_pad_set_getregion_function (GstPad *pad,
g_return_if_fail (GST_IS_REAL_PAD (pad)); g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_GETREGIONFUNC(pad) = getregion; GST_RPAD_GETREGIONFUNC(pad) = getregion;
GST_DEBUG (0,"getregionfunc for %s:%s(@%p) at %p is set to %p\n", GST_DEBUG (GST_CAT_PADS,"getregionfunc for %s:%s set to %s\n",
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_GETREGIONFUNC(pad),getregion); GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(getregion));
} }
/** /**
@ -387,8 +407,8 @@ gst_pad_set_qos_function (GstPad *pad,
g_return_if_fail (GST_IS_REAL_PAD (pad)); g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_QOSFUNC(pad) = qos; GST_RPAD_QOSFUNC(pad) = qos;
GST_DEBUG (0,"qosfunc for %s:%s(@%p) at %p is set to %p\n", GST_DEBUG (GST_CAT_PADS,"qosfunc for %s:%s set to %s\n",
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_QOSFUNC(pad),qos); GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(qos));
} }
/** /**
@ -406,8 +426,8 @@ gst_pad_set_eos_function (GstPad *pad,
g_return_if_fail (GST_IS_REAL_PAD (pad)); g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_EOSFUNC(pad) = eos; GST_RPAD_EOSFUNC(pad) = eos;
GST_DEBUG (0,"eosfunc for %s:%s(@%p) at %p is set to %p\n", GST_DEBUG (GST_CAT_PADS,"eosfunc for %s:%s set to %s\n",
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_EOSFUNC(pad),eos); GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(eos));
} }
/** /**
@ -425,11 +445,10 @@ gst_pad_set_negotiate_function (GstPad *pad,
g_return_if_fail (GST_IS_REAL_PAD (pad)); g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_NEGOTIATEFUNC(pad) = nego; GST_RPAD_NEGOTIATEFUNC(pad) = nego;
GST_DEBUG (0,"negotiatefunc for %s:%s(@%p) at %p is set to %p\n", GST_DEBUG (GST_CAT_PADS,"negotiatefunc for %s:%s set to %s\n",
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_NEGOTIATEFUNC(pad),nego); GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(nego));
} }
/** /**
* gst_pad_set_newcaps_function: * gst_pad_set_newcaps_function:
* @pad: the pad to set the newcaps function for * @pad: the pad to set the newcaps function for
@ -445,8 +464,8 @@ gst_pad_set_newcaps_function (GstPad *pad,
g_return_if_fail (GST_IS_REAL_PAD (pad)); g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_NEWCAPSFUNC (pad) = newcaps; GST_RPAD_NEWCAPSFUNC (pad) = newcaps;
GST_DEBUG (0,"newcapsfunc for %s:%s(@%p) at %p is set to %p\n", GST_DEBUG (GST_CAT_PADS,"newcapsfunc for %s:%s set to %s\n",
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_NEWCAPSFUNC(pad),newcaps); GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(newcaps));
} }
/** /**
@ -464,18 +483,19 @@ gst_pad_set_bufferpool_function (GstPad *pad,
g_return_if_fail (GST_IS_REAL_PAD (pad)); g_return_if_fail (GST_IS_REAL_PAD (pad));
GST_RPAD_BUFFERPOOLFUNC (pad) = bufpool; GST_RPAD_BUFFERPOOLFUNC (pad) = bufpool;
GST_DEBUG (0,"bufferpoolfunc for %s:%s(@%p) at %p is set to %p\n", GST_DEBUG (GST_CAT_PADS,"bufferpoolfunc for %s:%s set to %s\n",
GST_DEBUG_PAD_NAME (pad), pad, &GST_RPAD_BUFFERPOOLFUNC (pad), bufpool); GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME(bufpool));
} }
static void static void
gst_pad_push_func(GstPad *pad, GstBuffer *buf) gst_pad_push_func(GstPad *pad, GstBuffer *buf)
{ {
if (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)) != NULL) { if (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)) != NULL) {
GST_DEBUG (0,"calling chain function\n"); GST_DEBUG (GST_CAT_DATAFLOW,"calling chain function %s\n",
GST_DEBUG_FUNCPTR_NAME(GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad))));
(GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)))(pad,buf); (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)))(pad,buf);
} else { } else {
GST_DEBUG (0,"got a problem here: default pad_push handler in place, no chain function\n"); GST_DEBUG (GST_CAT_DATAFLOW,"got a problem here: default pad_push handler in place, no chain function\n");
} }
} }
@ -495,7 +515,7 @@ gst_pad_handle_qos(GstPad *pad,
GList *pads; GList *pads;
GstPad *target_pad; GstPad *target_pad;
GST_DEBUG (0,"gst_pad_handle_qos(\"%s\",%08ld)\n", GST_OBJECT_NAME (GST_PAD_PARENT (pad)),qos_message); GST_DEBUG (GST_CAT_PADS,"gst_pad_handle_qos(\"%s\",%08ld)\n", GST_OBJECT_NAME (GST_PAD_PARENT (pad)),qos_message);
if (GST_RPAD_QOSFUNC(pad)) { if (GST_RPAD_QOSFUNC(pad)) {
(GST_RPAD_QOSFUNC(pad)) (pad,qos_message); (GST_RPAD_QOSFUNC(pad)) (pad,qos_message);
@ -503,7 +523,7 @@ gst_pad_handle_qos(GstPad *pad,
element = GST_ELEMENT (GST_PAD_PARENT(GST_RPAD_PEER(pad))); element = GST_ELEMENT (GST_PAD_PARENT(GST_RPAD_PEER(pad)));
pads = element->pads; pads = element->pads;
GST_DEBUG (0,"gst_pad_handle_qos recurse(\"%s\",%08ld)\n", GST_ELEMENT_NAME (element), qos_message); GST_DEBUG (GST_CAT_PADS,"gst_pad_handle_qos recurse(\"%s\",%08ld)\n", GST_ELEMENT_NAME (element), qos_message);
while (pads) { while (pads) {
target_pad = GST_PAD (pads->data); target_pad = GST_PAD (pads->data);
if (GST_RPAD_DIRECTION(target_pad) == GST_PAD_SINK) { if (GST_RPAD_DIRECTION(target_pad) == GST_PAD_SINK) {
@ -535,6 +555,9 @@ gst_pad_disconnect (GstPad *srcpad,
g_return_if_fail (sinkpad != NULL); g_return_if_fail (sinkpad != NULL);
g_return_if_fail (GST_IS_PAD (sinkpad)); g_return_if_fail (GST_IS_PAD (sinkpad));
GST_INFO (GST_CAT_ELEMENT_PADS, "disconnecting %s:%s(%p) and %s:%s(%p)",
GST_DEBUG_PAD_NAME(srcpad), srcpad, GST_DEBUG_PAD_NAME(sinkpad), sinkpad);
// now we need to deal with the real/ghost stuff // now we need to deal with the real/ghost stuff
realsrc = GST_PAD_REALIZE(srcpad); realsrc = GST_PAD_REALIZE(srcpad);
realsink = GST_PAD_REALIZE(sinkpad); realsink = GST_PAD_REALIZE(sinkpad);
@ -542,6 +565,14 @@ gst_pad_disconnect (GstPad *srcpad,
g_return_if_fail (GST_RPAD_PEER(realsrc) != NULL); g_return_if_fail (GST_RPAD_PEER(realsrc) != NULL);
g_return_if_fail (GST_RPAD_PEER(realsink) != NULL); g_return_if_fail (GST_RPAD_PEER(realsink) != NULL);
if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) &&
(GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) {
GstRealPad *temppad;
temppad = realsrc;
realsrc = realsink;
realsink = temppad;
}
g_return_if_fail ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) && g_return_if_fail ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) &&
(GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK)); (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK));
@ -549,6 +580,16 @@ gst_pad_disconnect (GstPad *srcpad,
GST_RPAD_PEER(realsrc) = NULL; GST_RPAD_PEER(realsrc) = NULL;
GST_RPAD_PEER(realsink) = NULL; GST_RPAD_PEER(realsink) = NULL;
/* fire off a signal to each of the pads telling them that they've been disconnected */
gtk_signal_emit(GTK_OBJECT(realsrc), gst_real_pad_signals[REAL_DISCONNECTED], realsink);
gtk_signal_emit(GTK_OBJECT(realsink), gst_real_pad_signals[REAL_DISCONNECTED], realsrc);
// now tell the scheduler
if (realsrc->sched)
GST_SCHEDULE_PAD_DISCONNECT (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink);
// if (realsink->sched)
// GST_SCHEDULE_PAD_DISCONNECT (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink);
GST_INFO (GST_CAT_ELEMENT_PADS, "disconnected %s:%s and %s:%s", GST_INFO (GST_CAT_ELEMENT_PADS, "disconnected %s:%s and %s:%s",
GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
} }
@ -567,7 +608,6 @@ gst_pad_connect (GstPad *srcpad,
GstPad *sinkpad) GstPad *sinkpad)
{ {
GstRealPad *realsrc, *realsink; GstRealPad *realsrc, *realsink;
GstRealPad *temppad;
gboolean negotiated = FALSE; gboolean negotiated = FALSE;
/* generic checks */ /* generic checks */
@ -576,49 +616,69 @@ gst_pad_connect (GstPad *srcpad,
g_return_val_if_fail(sinkpad != NULL, FALSE); g_return_val_if_fail(sinkpad != NULL, FALSE);
g_return_val_if_fail(GST_IS_PAD(sinkpad), FALSE); g_return_val_if_fail(GST_IS_PAD(sinkpad), FALSE);
GST_INFO (GST_CAT_ELEMENT_PADS, "about to connect %s:%s and %s:%s", GST_INFO (GST_CAT_PADS, "connecting %s:%s and %s:%s",
GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad)); GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
// now we need to deal with the real/ghost stuff // now we need to deal with the real/ghost stuff
realsrc = GST_PAD_REALIZE(srcpad); realsrc = GST_PAD_REALIZE(srcpad);
realsink = GST_PAD_REALIZE(sinkpad); realsink = GST_PAD_REALIZE(sinkpad);
if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad))
GST_INFO (GST_CAT_PADS, "*actually* connecting %s:%s and %s:%s",
GST_DEBUG_PAD_NAME(realsrc), GST_DEBUG_PAD_NAME(realsink));
g_return_val_if_fail(GST_RPAD_PEER(realsrc) == NULL, FALSE); g_return_val_if_fail(GST_RPAD_PEER(realsrc) == NULL, FALSE);
g_return_val_if_fail(GST_RPAD_PEER(realsink) == NULL, FALSE); g_return_val_if_fail(GST_RPAD_PEER(realsink) == NULL, FALSE);
/* check for reversed directions and swap if necessary */ /* check for reversed directions and swap if necessary */
if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) && if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) &&
(GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) { (GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) {
GstRealPad *temppad;
temppad = realsrc; temppad = realsrc;
realsrc = realsink; realsrc = realsink;
realsink = temppad; realsink = temppad;
} }
g_return_val_if_fail((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) && g_return_val_if_fail((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) &&
(GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK), FALSE); (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK), FALSE);
/* first set peers */ /* first set peers */
GST_RPAD_PEER(realsrc) = realsink; GST_RPAD_PEER(realsrc) = realsink;
GST_RPAD_PEER(realsink) = realsrc; GST_RPAD_PEER(realsink) = realsrc;
/* FIXME: set connected flag */
GST_INFO (GST_CAT_ELEMENT_PADS, "connected %s:%s and %s:%s",
GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
if (GST_PAD_CAPS (srcpad)) { if (GST_PAD_CAPS (srcpad)) {
GST_DEBUG(GST_CAT_PADS, "renegotiation from srcpad\n");
negotiated = gst_pad_renegotiate (srcpad); negotiated = gst_pad_renegotiate (srcpad);
} }
else if (GST_PAD_CAPS (sinkpad)) { else if (GST_PAD_CAPS (sinkpad)) {
GST_DEBUG(GST_CAT_PADS, "renegotiation from sinkpad\n");
negotiated = gst_pad_renegotiate (sinkpad); negotiated = gst_pad_renegotiate (sinkpad);
} }
else else {
GST_DEBUG(GST_CAT_PADS, "not renegotiating connection\n");
negotiated = TRUE; negotiated = TRUE;
}
if (!negotiated) { if (!negotiated) {
GST_INFO(GST_CAT_PADS, "pads %s:%s and %s:%s failed to negotiate, disconnecting",
GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
gst_pad_disconnect (GST_PAD (realsrc), GST_PAD (realsink)); gst_pad_disconnect (GST_PAD (realsrc), GST_PAD (realsink));
return FALSE; return FALSE;
} }
/* fire off a signal to each of the pads telling them that they've been connected */
gtk_signal_emit(GTK_OBJECT(realsrc), gst_real_pad_signals[REAL_CONNECTED], realsink);
gtk_signal_emit(GTK_OBJECT(realsink), gst_real_pad_signals[REAL_CONNECTED], realsrc);
// now tell the scheduler(s)
if (realsrc->sched)
GST_SCHEDULE_PAD_CONNECT (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink);
else if (realsink->sched)
GST_SCHEDULE_PAD_CONNECT (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink);
GST_INFO (GST_CAT_PADS, "connected %s:%s and %s:%s",
GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
return TRUE; return TRUE;
} }
@ -668,13 +728,31 @@ gst_pad_get_padtemplate (GstPad *pad)
* *
* Returns: the parent object * Returns: the parent object
*/ */
GstObject* GstElement*
gst_pad_get_parent (GstPad *pad) gst_pad_get_parent (GstPad *pad)
{ {
g_return_val_if_fail (pad != NULL, NULL); g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD (pad), NULL); g_return_val_if_fail (GST_IS_PAD (pad), NULL);
return GST_OBJECT_PARENT (pad); return GST_PAD_PARENT (pad);
}
void
gst_pad_set_sched (GstPad *pad, GstSchedule *sched)
{
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
GST_RPAD_SCHED(pad) = sched;
}
GstSchedule*
gst_pad_get_sched (GstPad *pad)
{
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
return GST_RPAD_SCHED(pad);
} }
/** /**
@ -687,7 +765,7 @@ gst_pad_get_parent (GstPad *pad)
* *
* Returns: the parent object * Returns: the parent object
*/ */
GstObject* GstElement*
gst_pad_get_real_parent (GstPad *pad) gst_pad_get_real_parent (GstPad *pad)
{ {
g_return_val_if_fail (pad != NULL, NULL); g_return_val_if_fail (pad != NULL, NULL);
@ -892,7 +970,7 @@ gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
} }
} }
else { else {
GST_DEBUG (0,"gstpad: could not check capabilities of pads (%s:%s) and (%s:%s) %p %p\n", GST_DEBUG (GST_CAT_PADS,"could not check capabilities of pads (%s:%s) and (%s:%s) %p %p\n",
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad), GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad),
GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad)); GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad));
return TRUE; return TRUE;
@ -940,25 +1018,51 @@ gst_pad_get_bufferpool (GstPad *pad)
GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad)); GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
if (peer->bufferpoolfunc) { if (peer->bufferpoolfunc) {
GST_DEBUG (0,"calling bufferpoolfunc &%s (@%p) of peer pad %s:%s\n", GST_DEBUG (GST_CAT_PADS,"calling bufferpoolfunc &%s (@%p) of peer pad %s:%s\n",
GST_DEBUG_FUNCPTR_NAME(peer->bufferpoolfunc),&peer->bufferpoolfunc,GST_DEBUG_PAD_NAME(((GstPad*)peer))); GST_DEBUG_FUNCPTR_NAME(peer->bufferpoolfunc),&peer->bufferpoolfunc,GST_DEBUG_PAD_NAME(((GstPad*)peer)));
return (peer->bufferpoolfunc)(((GstPad*)peer)); return (peer->bufferpoolfunc)(((GstPad*)peer));
} else { } else {
GST_DEBUG (0,"no bufferpoolfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->bufferpoolfunc); GST_DEBUG (GST_CAT_PADS,"no bufferpoolfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->bufferpoolfunc);
return NULL; return NULL;
} }
} }
// FIXME this needs to be rethought soon
static void static void
gst_real_pad_destroy (GtkObject *object) gst_real_pad_destroy (GtkObject *object)
{ {
GstPad *pad = GST_PAD (object); GstPad *pad = GST_PAD (object);
// g_print("in gst_pad_real_destroy()\n"); GST_DEBUG (GST_CAT_REFCOUNTING, "destroy %s:%s\n", GST_DEBUG_PAD_NAME(pad));
g_list_free (GST_REAL_PAD(pad)->ghostpads); if (GST_PAD (pad)->padtemplate)
gst_object_unref (GST_OBJECT (GST_PAD (pad)->padtemplate));
if (GST_PAD_PEER (pad))
gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad)))
gst_element_remove_pad (GST_ELEMENT (GST_OBJECT_PARENT (pad)), pad);
// FIXME we should destroy the ghostpads, because they are nothing without the real pad
if (GST_REAL_PAD (pad)->ghostpads) {
GList *orig, *ghostpads;
orig = ghostpads = g_list_copy (GST_REAL_PAD (pad)->ghostpads);
while (ghostpads) {
GstPad *ghostpad = GST_PAD (ghostpads->data);
if (GST_IS_ELEMENT (GST_OBJECT_PARENT (ghostpad)))
gst_element_remove_pad (GST_ELEMENT (GST_OBJECT_PARENT (ghostpad)), ghostpad);
ghostpads = g_list_next (ghostpads);
}
g_list_free (orig);
g_list_free (GST_REAL_PAD(pad)->ghostpads);
}
if (GTK_OBJECT_CLASS (real_pad_parent_class)->destroy)
GTK_OBJECT_CLASS (real_pad_parent_class)->destroy (object);
} }
@ -1170,9 +1274,22 @@ gst_pad_renegotiate (GstPad *pad)
result = gst_pad_renegotiate_func (GST_PAD (currentpad), &data1, GST_PAD (otherpad), &data2, &newcaps); result = gst_pad_renegotiate_func (GST_PAD (currentpad), &data1, GST_PAD (otherpad), &data2, &newcaps);
if (!result) {
GST_DEBUG (GST_CAT_NEGOTIATION, "firing caps_nego_failed signal on %s:%s and %s:%s to give it a chance to succeed\n",
GST_DEBUG_PAD_NAME(currentpad),GST_DEBUG_PAD_NAME(otherpad));
gtk_signal_emit (GTK_OBJECT(currentpad),
gst_real_pad_signals[REAL_CAPS_NEGO_FAILED],&result);
gtk_signal_emit (GTK_OBJECT(otherpad),
gst_real_pad_signals[REAL_CAPS_NEGO_FAILED],&result);
if (result)
GST_DEBUG (GST_CAT_NEGOTIATION, "caps_nego_failed handler claims success at renego, believing\n");
}
if (result) { if (result) {
GST_DEBUG (GST_CAT_NEGOTIATION, "pads aggreed on caps :)\n"); GST_DEBUG (GST_CAT_NEGOTIATION, "pads aggreed on caps :)\n");
newcaps = GST_PAD_CAPS (pad);
/* here we have some sort of aggreement of the caps */ /* here we have some sort of aggreement of the caps */
GST_PAD_CAPS (currentpad) = gst_caps_ref (newcaps); GST_PAD_CAPS (currentpad) = gst_caps_ref (newcaps);
if (GST_RPAD_NEWCAPSFUNC (currentpad)) if (GST_RPAD_NEWCAPSFUNC (currentpad))
@ -1181,6 +1298,13 @@ gst_pad_renegotiate (GstPad *pad)
GST_PAD_CAPS (otherpad) = gst_caps_ref (newcaps); GST_PAD_CAPS (otherpad) = gst_caps_ref (newcaps);
if (GST_RPAD_NEWCAPSFUNC (otherpad)) if (GST_RPAD_NEWCAPSFUNC (otherpad))
GST_RPAD_NEWCAPSFUNC (otherpad) (GST_PAD (otherpad), newcaps); GST_RPAD_NEWCAPSFUNC (otherpad) (GST_PAD (otherpad), newcaps);
GST_DEBUG (GST_CAT_NEGOTIATION, "firing caps_changed signal on %s:%s and %s:%s\n",
GST_DEBUG_PAD_NAME(currentpad),GST_DEBUG_PAD_NAME(otherpad));
gtk_signal_emit (GTK_OBJECT(currentpad),
gst_real_pad_signals[REAL_CAPS_CHANGED],GST_PAD_CAPS(currentpad));
gtk_signal_emit (GTK_OBJECT(otherpad),
gst_real_pad_signals[REAL_CAPS_CHANGED],GST_PAD_CAPS(otherpad));
} }
return result; return result;
@ -1313,16 +1437,16 @@ gst_pad_push (GstPad *pad, GstBuffer *buf)
{ {
GstRealPad *peer = GST_RPAD_PEER (pad); GstRealPad *peer = GST_RPAD_PEER (pad);
g_return_if_fail (peer != NULL);
GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad)); GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
g_return_if_fail (peer != NULL);
if (peer->pushfunc) { if (peer->pushfunc) {
GST_DEBUG (0, "calling pushfunc &%s of peer pad %s:%s\n", GST_DEBUG (GST_CAT_DATAFLOW, "calling pushfunc &%s of peer pad %s:%s\n",
GST_DEBUG_FUNCPTR_NAME (peer->pushfunc), GST_DEBUG_PAD_NAME (((GstPad*)peer))); GST_DEBUG_FUNCPTR_NAME (peer->pushfunc), GST_DEBUG_PAD_NAME (((GstPad*)peer)));
(peer->pushfunc) (((GstPad*)peer), buf); (peer->pushfunc) (((GstPad*)peer), buf);
} else } else
GST_DEBUG (0, "no pushfunc\n"); GST_DEBUG (GST_CAT_DATAFLOW, "no pushfunc\n");
} }
#endif #endif
@ -1340,16 +1464,16 @@ gst_pad_pull (GstPad *pad)
{ {
GstRealPad *peer = GST_RPAD_PEER(pad); GstRealPad *peer = GST_RPAD_PEER(pad);
g_return_val_if_fail (peer != NULL, NULL);
GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad)); GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
g_return_val_if_fail (peer != NULL, NULL);
if (peer->pullfunc) { if (peer->pullfunc) {
GST_DEBUG (0,"calling pullfunc &%s (@%p) of peer pad %s:%s\n", GST_DEBUG (GST_CAT_DATAFLOW,"calling pullfunc %s of peer pad %s:%s\n",
GST_DEBUG_FUNCPTR_NAME(peer->pullfunc),&peer->pullfunc,GST_DEBUG_PAD_NAME(((GstPad*)peer))); GST_DEBUG_FUNCPTR_NAME(peer->pullfunc),GST_DEBUG_PAD_NAME(peer));
return (peer->pullfunc)(((GstPad*)peer)); return (peer->pullfunc)(((GstPad*)peer));
} else { } else {
GST_DEBUG (0,"no pullfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->pullfunc); GST_DEBUG (GST_CAT_DATAFLOW,"no pullfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->pullfunc);
return NULL; return NULL;
} }
} }
@ -1380,11 +1504,11 @@ gst_pad_pullregion (GstPad *pad, GstRegionType type, guint64 offset, guint64 len
GST_DEBUG_ENTER("(%s:%s,%d,%lld,%lld)",GST_DEBUG_PAD_NAME(pad),type,offset,len); GST_DEBUG_ENTER("(%s:%s,%d,%lld,%lld)",GST_DEBUG_PAD_NAME(pad),type,offset,len);
if (peer->pullregionfunc) { if (peer->pullregionfunc) {
GST_DEBUG (0,"calling pullregionfunc &%s of peer pad %s:%s\n", GST_DEBUG (GST_CAT_DATAFLOW,"calling pullregionfunc &%s of peer pad %s:%s\n",
GST_DEBUG_FUNCPTR_NAME(peer->pullregionfunc),GST_DEBUG_PAD_NAME(((GstPad*)peer))); GST_DEBUG_FUNCPTR_NAME(peer->pullregionfunc),GST_DEBUG_PAD_NAME(((GstPad*)peer)));
return (peer->pullregionfunc)(((GstPad*)peer),type,offset,len); return (peer->pullregionfunc)(((GstPad*)peer),type,offset,len);
} else { } else {
GST_DEBUG (0,"no pullregionfunc\n"); GST_DEBUG (GST_CAT_DATAFLOW,"no pullregionfunc\n");
return NULL; return NULL;
} }
} }
@ -1528,7 +1652,7 @@ gst_padtemplate_save_thyself (GstPadTemplate *templ, xmlNodePtr parent)
xmlNodePtr subtree; xmlNodePtr subtree;
guchar *presence; guchar *presence;
GST_DEBUG (0,"saving padtemplate %s\n", templ->name_template); GST_DEBUG (GST_CAT_XML,"saving padtemplate %s\n", templ->name_template);
xmlNewChild(parent,NULL,"nametemplate", templ->name_template); xmlNewChild(parent,NULL,"nametemplate", templ->name_template);
xmlNewChild(parent,NULL,"direction", (templ->direction == GST_PAD_SINK? "sink":"src")); xmlNewChild(parent,NULL,"direction", (templ->direction == GST_PAD_SINK? "sink":"src"));
@ -1616,7 +1740,7 @@ gst_padtemplate_load_thyself (xmlNodePtr parent)
} }
static gboolean gboolean
gst_pad_eos_func(GstPad *pad) gst_pad_eos_func(GstPad *pad)
{ {
GstElement *element; GstElement *element;
@ -1649,6 +1773,8 @@ gst_pad_eos_func(GstPad *pad)
GST_INFO (GST_CAT_PADS,"set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad)); GST_INFO (GST_CAT_PADS,"set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad));
GST_FLAG_SET (pad, GST_PAD_EOS); GST_FLAG_SET (pad, GST_PAD_EOS);
gst_element_set_state (GST_ELEMENT(GST_PAD_PARENT(pad)), GST_STATE_READY);
return TRUE; return TRUE;
} }
@ -1676,6 +1802,8 @@ gst_pad_set_eos(GstPad *pad)
GST_INFO (GST_CAT_PADS,"set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad)); GST_INFO (GST_CAT_PADS,"set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad));
GST_FLAG_SET (pad, GST_PAD_EOS); GST_FLAG_SET (pad, GST_PAD_EOS);
gst_element_set_state (GST_ELEMENT(GST_PAD_PARENT(pad)), GST_STATE_READY);
gst_element_signal_eos (GST_ELEMENT (GST_PAD_PARENT (pad))); gst_element_signal_eos (GST_ELEMENT (GST_PAD_PARENT (pad)));
return TRUE; return TRUE;
@ -1783,7 +1911,7 @@ gst_ghost_pad_new (gchar *name,
// FIXME need to ref the real pad here... ? // FIXME need to ref the real pad here... ?
GST_DEBUG(0,"created ghost pad \"%s\"\n",name); GST_DEBUG(GST_CAT_PADS,"created ghost pad \"%s\"\n",name);
return GST_PAD(ghostpad); return GST_PAD(ghostpad);
} }

View file

@ -63,14 +63,14 @@ extern "C" {
#define GST_IS_GHOST_PAD_CLASS(obj) (GTK_CHECK_CLASS_TYPE ((klass), GST_TYPE_GHOST_PAD)) #define GST_IS_GHOST_PAD_CLASS(obj) (GTK_CHECK_CLASS_TYPE ((klass), GST_TYPE_GHOST_PAD))
typedef struct _GstPad GstPad; //typedef struct _GstPad GstPad;
typedef struct _GstPadClass GstPadClass; //typedef struct _GstPadClass GstPadClass;
typedef struct _GstRealPad GstRealPad; typedef struct _GstRealPad GstRealPad;
typedef struct _GstRealPadClass GstRealPadClass; typedef struct _GstRealPadClass GstRealPadClass;
typedef struct _GstGhostPad GstGhostPad; typedef struct _GstGhostPad GstGhostPad;
typedef struct _GstGhostPadClass GstGhostPadClass; typedef struct _GstGhostPadClass GstGhostPadClass;
typedef struct _GstPadTemplate GstPadTemplate; //typedef struct _GstPadTemplate GstPadTemplate;
typedef struct _GstPadTemplateClass GstPadTemplateClass; //typedef struct _GstPadTemplateClass GstPadTemplateClass;
typedef enum { typedef enum {
@ -142,6 +142,8 @@ struct _GstRealPad {
guint64 offset; guint64 offset;
guint64 len; guint64 len;
GstSchedule *sched;
GstPadChainFunction chainfunc; GstPadChainFunction chainfunc;
GstPadGetFunction getfunc; GstPadGetFunction getfunc;
GstPadGetRegionFunction getregionfunc; GstPadGetRegionFunction getregionfunc;
@ -163,9 +165,13 @@ struct _GstRealPadClass {
GstPadClass parent_class; GstPadClass parent_class;
/* signal callbacks */ /* signal callbacks */
void (*set_active) (GstPad *pad, gboolean active); void (*set_active) (GstPad *pad, gboolean active);
void (*caps_changed) (GstPad *pad, GstCaps *newcaps); void (*caps_changed) (GstPad *pad, GstCaps *newcaps);
void (*eos) (GstPad *pad); void (*caps_nego_failed) (GstPad *pad);
void (*connected) (GstPad *pad, GstPad *peer);
void (*disconnected) (GstPad *pad, GstPad *peer);
void (*eos) (GstPad *pad);
}; };
struct _GstGhostPad { struct _GstGhostPad {
@ -182,7 +188,7 @@ struct _GstGhostPadClass {
/***** helper macros *****/ /***** helper macros *****/
/* GstPad */ /* GstPad */
#define GST_PAD_NAME(pad) (GST_OBJECT_NAME(pad)) #define GST_PAD_NAME(pad) (GST_OBJECT_NAME(pad))
#define GST_PAD_PARENT(pad) (GST_OBJECT_PARENT(pad)) #define GST_PAD_PARENT(pad) ((GstElement *)(GST_OBJECT_PARENT(pad)))
#define GST_PAD_ELEMENT_PRIVATE(pad) (((GstPad *)(pad))->element_private) #define GST_PAD_ELEMENT_PRIVATE(pad) (((GstPad *)(pad))->element_private)
#define GST_PAD_PADTEMPLATE(pad) (((GstPad *)(pad))->padtemplate) #define GST_PAD_PADTEMPLATE(pad) (((GstPad *)(pad))->padtemplate)
@ -191,6 +197,7 @@ struct _GstGhostPadClass {
#define GST_RPAD_CAPS(pad) (((GstRealPad *)(pad))->caps) #define GST_RPAD_CAPS(pad) (((GstRealPad *)(pad))->caps)
#define GST_RPAD_PEER(pad) (((GstRealPad *)(pad))->peer) #define GST_RPAD_PEER(pad) (((GstRealPad *)(pad))->peer)
#define GST_RPAD_BUFPEN(pad) (((GstRealPad *)(pad))->bufpen) #define GST_RPAD_BUFPEN(pad) (((GstRealPad *)(pad))->bufpen)
#define GST_RPAD_SCHED(pad) (((GstRealPad *)(pad))->sched)
#define GST_RPAD_CHAINFUNC(pad) (((GstRealPad *)(pad))->chainfunc) #define GST_RPAD_CHAINFUNC(pad) (((GstRealPad *)(pad))->chainfunc)
#define GST_RPAD_GETFUNC(pad) (((GstRealPad *)(pad))->getfunc) #define GST_RPAD_GETFUNC(pad) (((GstRealPad *)(pad))->getfunc)
#define GST_RPAD_GETREGIONFUNC(pad) (((GstRealPad *)(pad))->getregionfunc) #define GST_RPAD_GETREGIONFUNC(pad) (((GstRealPad *)(pad))->getregionfunc)
@ -312,8 +319,11 @@ void gst_pad_set_name (GstPad *pad, const gchar *name);
const gchar* gst_pad_get_name (GstPad *pad); const gchar* gst_pad_get_name (GstPad *pad);
void gst_pad_set_parent (GstPad *pad, GstObject *parent); void gst_pad_set_parent (GstPad *pad, GstObject *parent);
GstObject* gst_pad_get_parent (GstPad *pad); GstElement* gst_pad_get_parent (GstPad *pad);
GstObject* gst_pad_get_real_parent (GstPad *pad); GstElement* gst_pad_get_real_parent (GstPad *pad);
void gst_pad_set_sched (GstPad *pad, GstSchedule *sched);
GstSchedule* gst_pad_get_sched (GstPad *pad);
void gst_pad_add_ghost_pad (GstPad *pad, GstPad *ghostpad); void gst_pad_add_ghost_pad (GstPad *pad, GstPad *ghostpad);
void gst_pad_remove_ghost_pad (GstPad *pad, GstPad *ghostpad); void gst_pad_remove_ghost_pad (GstPad *pad, GstPad *ghostpad);
@ -356,6 +366,7 @@ NULL )
#define gst_pad_eos(pad) (GST_RPAD_EOSFUNC(GST_RPAD_PEER(pad))(GST_PAD(GST_RPAD_PEER(pad)))) #define gst_pad_eos(pad) (GST_RPAD_EOSFUNC(GST_RPAD_PEER(pad))(GST_PAD(GST_RPAD_PEER(pad))))
gboolean gst_pad_set_eos (GstPad *pad); gboolean gst_pad_set_eos (GstPad *pad);
gboolean gst_pad_eos_func (GstPad *pad);
void gst_pad_handle_qos (GstPad *pad, glong qos_message); void gst_pad_handle_qos (GstPad *pad, glong qos_message);
void gst_pad_load_and_connect (xmlNodePtr self, GstObject *parent); void gst_pad_load_and_connect (xmlNodePtr self, GstObject *parent);
@ -379,6 +390,7 @@ GstCaps* gst_padtemplate_get_caps_by_name (GstPadTemplate *templ, const gchar *
xmlNodePtr gst_padtemplate_save_thyself (GstPadTemplate *templ, xmlNodePtr parent); xmlNodePtr gst_padtemplate_save_thyself (GstPadTemplate *templ, xmlNodePtr parent);
GstPadTemplate* gst_padtemplate_load_thyself (xmlNodePtr parent); GstPadTemplate* gst_padtemplate_load_thyself (xmlNodePtr parent);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View file

@ -24,6 +24,11 @@
#include "gst_private.h" #include "gst_private.h"
#include "gstpipeline.h" #include "gstpipeline.h"
#include "gstthread.h"
#include "gstutils.h"
#include "gsttype.h"
#include "gstautoplug.h"
#include "gstscheduler.h"
GstElementDetails gst_pipeline_details = { GstElementDetails gst_pipeline_details = {
@ -95,6 +100,10 @@ gst_pipeline_init (GstPipeline *pipeline)
{ {
// we're a manager by default // we're a manager by default
GST_FLAG_SET (pipeline, GST_BIN_FLAG_MANAGER); GST_FLAG_SET (pipeline, GST_BIN_FLAG_MANAGER);
GST_ELEMENT_SCHED(pipeline) = gst_schedule_new(GST_ELEMENT(pipeline));
GST_DEBUG(GST_CAT_PIPELINE, "pipeline's scheduler is %p\n",GST_ELEMENT_SCHED(pipeline));
// gst_element_set_manager(GST_ELEMENT(pipeline),GST_ELEMENT(pipeline));
} }
@ -107,16 +116,16 @@ gst_pipeline_init (GstPipeline *pipeline)
* Returns: newly created GstPipeline * Returns: newly created GstPipeline
*/ */
GstElement* GstElement*
gst_pipeline_new (const guchar *name) gst_pipeline_new (const guchar *name)
{ {
return gst_elementfactory_make ("pipeline", name); return gst_elementfactory_make ("pipeline", name);
} }
static void static void
gst_pipeline_prepare (GstPipeline *pipeline) gst_pipeline_prepare (GstPipeline *pipeline)
{ {
GST_DEBUG (0,"GstPipeline: preparing pipeline \"%s\" for playing\n", GST_DEBUG (GST_CAT_PIPELINE,"preparing pipeline \"%s\" for playing (DEPRACATED!!)\n",
GST_ELEMENT_NAME(GST_ELEMENT(pipeline))); GST_ELEMENT_NAME(GST_ELEMENT(pipeline)));
} }
static GstElementStateReturn static GstElementStateReturn

View file

@ -53,19 +53,19 @@ gst_props_debug_entry (GstPropsEntry *entry)
{ {
switch (entry->propstype) { switch (entry->propstype) {
case GST_PROPS_INT_ID: case GST_PROPS_INT_ID:
GST_DEBUG (0, "%d\n", entry->data.int_data); GST_DEBUG (GST_CAT_PROPERTIES, "%d\n", entry->data.int_data);
break; break;
case GST_PROPS_FOURCC_ID: case GST_PROPS_FOURCC_ID:
GST_DEBUG (0, "%4.4s\n", (gchar*)&entry->data.fourcc_data); GST_DEBUG (GST_CAT_PROPERTIES, "%4.4s\n", (gchar*)&entry->data.fourcc_data);
break; break;
case GST_PROPS_BOOL_ID: case GST_PROPS_BOOL_ID:
GST_DEBUG (0, "%d\n", entry->data.bool_data); GST_DEBUG (GST_CAT_PROPERTIES, "%d\n", entry->data.bool_data);
break; break;
case GST_PROPS_STRING_ID: case GST_PROPS_STRING_ID:
GST_DEBUG (0, "%s\n", entry->data.string_data.string); GST_DEBUG (GST_CAT_PROPERTIES, "%s\n", entry->data.string_data.string);
break; break;
case GST_PROPS_INT_RANGE_ID: case GST_PROPS_INT_RANGE_ID:
GST_DEBUG (0, "%d-%d\n", entry->data.int_range_data.min, GST_DEBUG (GST_CAT_PROPERTIES, "%d-%d\n", entry->data.int_range_data.min,
entry->data.int_range_data.max); entry->data.int_range_data.max);
break; break;
default: default:
@ -616,7 +616,7 @@ gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *
static gboolean static gboolean
gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2) gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
{ {
GST_DEBUG (0,"compare: %s %s\n", g_quark_to_string (entry1->propid), GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s\n", g_quark_to_string (entry1->propid),
g_quark_to_string (entry2->propid)); g_quark_to_string (entry2->propid));
switch (entry1->propstype) { switch (entry1->propstype) {
case GST_PROPS_LIST_ID: case GST_PROPS_LIST_ID:
@ -674,10 +674,13 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry
switch (entry2->propstype) { switch (entry2->propstype) {
// b <---> a - d // b <---> a - d
case GST_PROPS_INT_RANGE_ID: case GST_PROPS_INT_RANGE_ID:
GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?\n",entry2->data.int_range_data.min,
entry1->data.int_data,entry2->data.int_range_data.max);
return (entry2->data.int_range_data.min <= entry1->data.int_data && return (entry2->data.int_range_data.min <= entry1->data.int_data &&
entry2->data.int_range_data.max >= entry1->data.int_data); entry2->data.int_range_data.max >= entry1->data.int_data);
// b <---> a // b <---> a
case GST_PROPS_INT_ID: case GST_PROPS_INT_ID:
GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?\n",entry1->data.int_data,entry2->data.int_data);
return (entry2->data.int_data == entry1->data.int_data); return (entry2->data.int_data == entry1->data.int_data);
// b <---> a,b,c // b <---> a,b,c
case GST_PROPS_LIST_ID: case GST_PROPS_LIST_ID:
@ -761,14 +764,14 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
entry2 = (GstPropsEntry *)sinklist->data; entry2 = (GstPropsEntry *)sinklist->data;
while (entry1->propid < entry2->propid) { while (entry1->propid < entry2->propid) {
GST_DEBUG (0,"source is more specific in \"%s\"\n", g_quark_to_string (entry1->propid)); GST_DEBUG (GST_CAT_PROPERTIES,"source is more specific in \"%s\"\n", g_quark_to_string (entry1->propid));
more++; more++;
sourcelist = g_list_next (sourcelist); sourcelist = g_list_next (sourcelist);
if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data; if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
else goto end; else goto end;
} }
while (entry1->propid > entry2->propid) { while (entry1->propid > entry2->propid) {
GST_DEBUG (0,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid)); GST_DEBUG (GST_CAT_PROPERTIES,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
missing++; missing++;
sinklist = g_list_next (sinklist); sinklist = g_list_next (sinklist);
if (sinklist) entry2 = (GstPropsEntry *)sinklist->data; if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
@ -777,7 +780,7 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
if (!gst_props_entry_check_compatibility (entry1, entry2)) { if (!gst_props_entry_check_compatibility (entry1, entry2)) {
compatible = FALSE; compatible = FALSE;
GST_DEBUG (0, "%s are not compatible\n:", GST_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: \n",
g_quark_to_string (entry1->propid)); g_quark_to_string (entry1->propid));
gst_props_debug_entry (entry1); gst_props_debug_entry (entry1);
gst_props_debug_entry (entry2); gst_props_debug_entry (entry2);
@ -790,7 +793,7 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
GstPropsEntry *entry2; GstPropsEntry *entry2;
entry2 = (GstPropsEntry *)sinklist->data; entry2 = (GstPropsEntry *)sinklist->data;
missing++; missing++;
GST_DEBUG (0,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid)); GST_DEBUG (GST_CAT_PROPERTIES,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
} }
end: end:

View file

@ -23,7 +23,7 @@
//#define DEBUG_ENABLED //#define DEBUG_ENABLED
//#define STATUS_ENABLED //#define STATUS_ENABLED
#ifdef STATUS_ENABLED #ifdef STATUS_ENABLED
#define STATUS(A) GST_DEBUG(0,A, gst_element_get_name(GST_ELEMENT(queue))) #define STATUS(A) GST_DEBUG(GST_CAT_DATAFLOW, A, GST_ELEMENT_NAME(queue))
#else #else
#define STATUS(A) #define STATUS(A)
#endif #endif
@ -34,6 +34,7 @@
#include "gst_private.h" #include "gst_private.h"
#include "gstqueue.h" #include "gstqueue.h"
#include "gstscheduler.h"
GstElementDetails gst_queue_details = { GstElementDetails gst_queue_details = {
"Queue", "Queue",
@ -47,15 +48,22 @@ GstElementDetails gst_queue_details = {
/* Queue signals and args */ /* Queue signals and args */
enum { enum {
/* FILL ME */ LOW_WATERMARK,
HIGH_WATERMARK,
LAST_SIGNAL LAST_SIGNAL
}; };
enum { enum {
ARG_0, ARG_0,
ARG_LEVEL_BUFFERS,
ARG_LEVEL_BYTES,
ARG_LEVEL_TIME,
ARG_SIZE_BUFFERS,
ARG_SIZE_BYTES,
ARG_SIZE_TIME,
ARG_LEAKY,
ARG_LEVEL, ARG_LEVEL,
ARG_MAX_LEVEL, ARG_MAX_LEVEL,
ARG_BLOCK,
}; };
@ -76,6 +84,23 @@ static void gst_queue_flush (GstQueue *queue);
static GstElementStateReturn gst_queue_change_state (GstElement *element); static GstElementStateReturn gst_queue_change_state (GstElement *element);
static GtkType
queue_leaky_get_type(void) {
static GtkType queue_leaky_type = 0;
static GtkEnumValue queue_leaky[] = {
{ GST_QUEUE_NO_LEAK, "0", "Not Leaky" },
{ GST_QUEUE_LEAK_UPSTREAM, "1", "Leaky on Upstream" },
{ GST_QUEUE_LEAK_DOWNSTREAM, "2", "Leaky on Downstream" },
{ 0, NULL, NULL },
};
if (!queue_leaky_type) {
queue_leaky_type = gtk_type_register_enum("GstQueueLeaky", queue_leaky);
}
return queue_leaky_type;
}
#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type())
static GstElementClass *parent_class = NULL; static GstElementClass *parent_class = NULL;
//static guint gst_queue_signals[LAST_SIGNAL] = { 0 }; //static guint gst_queue_signals[LAST_SIGNAL] = { 0 };
@ -111,12 +136,12 @@ gst_queue_class_init (GstQueueClass *klass)
parent_class = gtk_type_class (GST_TYPE_ELEMENT); parent_class = gtk_type_class (GST_TYPE_ELEMENT);
gtk_object_add_arg_type ("GstQueue::leaky", GST_TYPE_QUEUE_LEAKY,
GTK_ARG_READWRITE, ARG_LEAKY);
gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT, gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT,
GTK_ARG_READABLE, ARG_LEVEL); GTK_ARG_READABLE, ARG_LEVEL);
gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT, gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT,
GTK_ARG_READWRITE, ARG_MAX_LEVEL); GTK_ARG_READWRITE, ARG_MAX_LEVEL);
gtk_object_add_arg_type ("GstQueue::block", GTK_TYPE_BOOL,
GTK_ARG_READWRITE, ARG_BLOCK);
gtkobject_class->set_arg = gst_queue_set_arg; gtkobject_class->set_arg = gst_queue_set_arg;
gtkobject_class->get_arg = gst_queue_get_arg; gtkobject_class->get_arg = gst_queue_get_arg;
@ -144,14 +169,15 @@ gst_queue_init (GstQueue *queue)
queue->queue = NULL; queue->queue = NULL;
queue->level_buffers = 0; queue->level_buffers = 0;
queue->max_buffers = 100;
queue->block = TRUE;
queue->level_bytes = 0; queue->level_bytes = 0;
queue->size_buffers = 0; queue->level_time = 0LL;
queue->size_bytes = 0; queue->size_buffers = 100; // 100 buffers
queue->size_bytes = 100 * 1024; // 100KB
queue->size_time = 1000000000LL; // 1sec
queue->emptycond = g_cond_new (); queue->emptycond = g_cond_new ();
queue->fullcond = g_cond_new (); queue->fullcond = g_cond_new ();
GST_DEBUG(GST_CAT_THREAD, "initialized queue's emptycond and fullcond\n");
} }
static GstBufferPool* static GstBufferPool*
@ -206,10 +232,10 @@ gst_queue_handle_eos (GstPad *pad)
queue = GST_QUEUE (GST_OBJECT_PARENT (pad)); queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
GST_DEBUG (0,"queue: %s received eos\n", GST_ELEMENT_NAME (queue)); GST_DEBUG (GST_CAT_DATAFLOW,"%s received eos\n", GST_ELEMENT_NAME (queue));
GST_LOCK (queue); GST_LOCK (queue);
GST_DEBUG (0,"queue: %s has %d buffers left\n", GST_ELEMENT_NAME (queue), GST_DEBUG (GST_CAT_DATAFLOW,"%s has %d buffers left\n", GST_ELEMENT_NAME (queue),
queue->level_buffers); queue->level_buffers);
GST_FLAG_SET (pad, GST_PAD_EOS); GST_FLAG_SET (pad, GST_PAD_EOS);
@ -224,7 +250,7 @@ gst_queue_handle_eos (GstPad *pad)
static void static void
gst_queue_cleanup_buffers (gpointer data, const gpointer user_data) gst_queue_cleanup_buffers (gpointer data, const gpointer user_data)
{ {
GST_DEBUG (0,"queue: %s cleaning buffer %p\n", (gchar *)user_data, data); GST_DEBUG (GST_CAT_DATAFLOW,"%s cleaning buffer %p\n", (gchar *)user_data, data);
gst_buffer_unref (GST_BUFFER (data)); gst_buffer_unref (GST_BUFFER (data));
} }
@ -257,45 +283,79 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf)
/* we have to lock the queue since we span threads */ /* we have to lock the queue since we span threads */
GST_DEBUG (0,"queue: try have queue lock\n"); // GST_DEBUG (GST_CAT_DATAFLOW,"trying to get lock on queue \"%s\"\n",name);
GST_LOCK (queue); GST_LOCK (queue);
GST_DEBUG (0,"queue: %s adding buffer %p %ld\n", name, buf, pthread_self ());
GST_DEBUG (0,"queue: have queue lock\n");
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) { if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) {
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "buffer has FLUSH bit set, flushing queue\n");
gst_queue_flush (queue); gst_queue_flush (queue);
} }
GST_DEBUG (0,"queue: %s: chain %d %p\n", name, queue->level_buffers, buf); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "adding buffer %p of size %d\n",buf,GST_BUFFER_SIZE(buf));
while (queue->level_buffers >= queue->max_buffers) { if (queue->level_buffers >= queue->size_buffers) {
GST_DEBUG (0,"queue: %s waiting %d\n", name, queue->level_buffers); // if this is a leaky queue...
STATUS("%s: O\n"); if (queue->leaky) {
//g_cond_timed_wait (queue->fullcond, queue->fulllock, queue->timeval); // if we leak on the upstream side, drop the current buffer
//FIXME need to signal other thread in case signals got lost? if (queue->leaky == GST_QUEUE_LEAK_UPSTREAM) {
g_cond_signal (queue->emptycond); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on upstream end\n");
g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock); gst_buffer_unref(buf);
STATUS("%s: O+\n"); // now we have to clean up and exit right away
GST_DEBUG (0,"queue: %s waiting done %d\n", name, queue->level_buffers); GST_UNLOCK (queue);
return;
}
// otherwise we have to push a buffer off the other end
else {
GSList *front;
GstBuffer *leakbuf;
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end\n");
front = queue->queue;
leakbuf = (GstBuffer *)(front->data);
queue->level_buffers--;
queue->level_bytes -= GST_BUFFER_SIZE(leakbuf);
gst_buffer_unref(leakbuf);
queue->queue = g_slist_remove_link (queue->queue, front);
g_slist_free (front);
}
}
while (queue->level_buffers >= queue->size_buffers) {
// if there's a pending state change for this queue or its manager, switch
// back to iterator so bottom half of state change executes
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
// GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->sinkpad))))) !=
GST_STATE_NONE_PENDING)
{
GST_DEBUG(GST_CAT_DATAFLOW,"interrupted!!\n");
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)\n");
if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING\n");
GST_UNLOCK(queue);
cothread_switch(cothread_current_main());
}
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for space, level is %d\n", queue->level_buffers);
g_cond_signal (queue->emptycond);
g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock);
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "done waiting, level is now %d\n", queue->level_buffers);
}
} }
/* put the buffer on the tail of the list */ /* put the buffer on the tail of the list */
queue->queue = g_slist_append (queue->queue, buf); queue->queue = g_slist_append (queue->queue, buf);
// STATUS("%s: +\n"); queue->level_buffers++;
GST_DEBUG (0,"(%s:%s)+ ",GST_DEBUG_PAD_NAME(pad)); queue->level_bytes += GST_BUFFER_SIZE(buf);
// GST_DEBUG (GST_CAT_DATAFLOW, "(%s:%s)+\n",GST_DEBUG_PAD_NAME(pad));
/* if we were empty, but aren't any more, signal a condition */ /* if we were empty, but aren't any more, signal a condition */
tosignal = (queue->level_buffers >= 0); if (queue->level_buffers == 1)
queue->level_buffers++; {
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling emptycond\n", name);
/* we can unlock now */
GST_DEBUG (0,"queue: %s chain %d end signal(%d,%p)\n", name, queue->level_buffers, tosignal, queue->emptycond);
if (tosignal) {
// STATUS("%s: >\n");
g_cond_signal (queue->emptycond); g_cond_signal (queue->emptycond);
// STATUS("%s: >>\n");
} }
GST_UNLOCK (queue); GST_UNLOCK (queue);
} }
@ -307,6 +367,8 @@ gst_queue_get (GstPad *pad)
GSList *front; GSList *front;
const guchar *name; const guchar *name;
g_assert(pad != NULL);
g_assert(GST_IS_PAD(pad));
g_return_val_if_fail (pad != NULL, NULL); g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD (pad), NULL); g_return_val_if_fail (GST_IS_PAD (pad), NULL);
@ -314,63 +376,74 @@ gst_queue_get (GstPad *pad)
name = GST_ELEMENT_NAME (queue); name = GST_ELEMENT_NAME (queue);
/* have to lock for thread-safety */ /* have to lock for thread-safety */
GST_DEBUG (0,"queue: %s try have queue lock\n", name); GST_DEBUG (GST_CAT_DATAFLOW,"%s try have queue lock\n", name);
GST_LOCK (queue); GST_LOCK (queue);
GST_DEBUG (0,"queue: %s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond); GST_DEBUG (GST_CAT_DATAFLOW,"%s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
GST_DEBUG (0,"queue: %s have queue lock\n", name); GST_DEBUG (GST_CAT_DATAFLOW,"%s have queue lock\n", name);
// we bail if there's nothing there
if (!queue->level_buffers && !queue->block) {
GST_UNLOCK(queue);
return NULL;
}
while (!queue->level_buffers) { while (!queue->level_buffers) {
STATUS("queue: %s U released lock\n");
//g_cond_timed_wait (queue->emptycond, queue->emptylock, queue->timeval);
if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) { if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) {
GST_DEBUG (GST_CAT_DATAFLOW, "%s U released lock\n", name);
GST_UNLOCK(queue);
gst_pad_set_eos (queue->srcpad); gst_pad_set_eos (queue->srcpad);
// this return NULL shouldn't hurt anything...
return NULL; return NULL;
} }
//FIXME need to signal other thread in case signals got lost?
// if there's a pending state change for this queue or its manager, switch
// back to iterator so bottom half of state change executes
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
// GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->srcpad))))) !=
GST_STATE_NONE_PENDING)
{
GST_DEBUG(GST_CAT_DATAFLOW,"interrupted!!\n");
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)\n");
if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING\n");
GST_UNLOCK(queue);
cothread_switch(cothread_current_main());
}
g_cond_signal (queue->fullcond); g_cond_signal (queue->fullcond);
g_cond_wait (queue->emptycond, GST_OBJECT(queue)->lock); g_cond_wait (queue->emptycond, GST_OBJECT(queue)->lock);
// STATUS("queue: %s U- getting lock\n");
} }
front = queue->queue; front = queue->queue;
buf = (GstBuffer *)(front->data); buf = (GstBuffer *)(front->data);
GST_DEBUG (0,"retrieved buffer %p from queue\n",buf); GST_DEBUG (GST_CAT_DATAFLOW,"retrieved buffer %p from queue\n",buf);
queue->queue = g_slist_remove_link (queue->queue, front); queue->queue = g_slist_remove_link (queue->queue, front);
g_slist_free (front); g_slist_free (front);
queue->level_buffers--; // if (queue->level_buffers < queue->size_buffers)
// STATUS("%s: -\n"); if (queue->level_buffers == queue->size_buffers)
GST_DEBUG (0,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad)); {
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling fullcond\n", name);
if (queue->level_buffers < queue->max_buffers) {
// STATUS("%s: < \n");
g_cond_signal (queue->fullcond); g_cond_signal (queue->fullcond);
// STATUS("%s: << \n");
} }
queue->level_buffers--;
queue->level_bytes -= GST_BUFFER_SIZE(buf);
GST_DEBUG (GST_CAT_DATAFLOW,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
GST_UNLOCK(queue); GST_UNLOCK(queue);
// GST_DEBUG (0,"queue: %s pushing %d %p \n", name, queue->level_buffers, buf);
// gst_pad_push (queue->srcpad, buf);
// GST_DEBUG (0,"queue: %s pushing %d done \n", name, queue->level_buffers);
return buf; return buf;
/* unlock now */
} }
static GstElementStateReturn static GstElementStateReturn
gst_queue_change_state (GstElement *element) gst_queue_change_state (GstElement *element)
{ {
GstQueue *queue; GstQueue *queue;
GstElementStateReturn ret;
g_return_val_if_fail (GST_IS_QUEUE (element), GST_STATE_FAILURE); g_return_val_if_fail (GST_IS_QUEUE (element), GST_STATE_FAILURE);
queue = GST_QUEUE (element); queue = GST_QUEUE (element);
GST_DEBUG (0,"gstqueue: state pending %d\n", GST_STATE_PENDING (element));
// lock the queue so another thread (not in sync with this thread's state)
// can't call this queue's _get (or whatever)
GST_LOCK (queue);
/* if going down into NULL state, clear out buffers*/ /* if going down into NULL state, clear out buffers*/
if (GST_STATE_PENDING (element) == GST_STATE_READY) { if (GST_STATE_PENDING (element) == GST_STATE_READY) {
@ -380,9 +453,41 @@ gst_queue_change_state (GstElement *element)
/* if we haven't failed already, give the parent class a chance to ;-) */ /* if we haven't failed already, give the parent class a chance to ;-) */
if (GST_ELEMENT_CLASS (parent_class)->change_state) if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element); {
gboolean valid_handler = FALSE;
guint state_change_id = gtk_signal_lookup("state_change", GTK_OBJECT_TYPE(element));
return GST_STATE_SUCCESS; // determine whether we need to block the parent (element) class'
// STATE_CHANGE signal so we can UNLOCK before returning. we block
// it if we could find the state_change signal AND there's a signal
// handler attached to it.
//
// note: this assumes that change_state() *only* emits state_change signal.
// if element change_state() emits other signals, they need to be blocked
// as well.
if (state_change_id &&
gtk_signal_handler_pending(GTK_OBJECT(element), state_change_id, FALSE))
valid_handler = TRUE;
if (valid_handler)
gtk_signal_handler_block(GTK_OBJECT(element), state_change_id);
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
if (valid_handler)
gtk_signal_handler_unblock(GTK_OBJECT(element), state_change_id);
// UNLOCK, *then* emit signal (if there's one there)
GST_UNLOCK(queue);
if (valid_handler)
gtk_signal_emit(GTK_OBJECT (element), state_change_id, GST_STATE(element));
}
else
{
ret = GST_STATE_SUCCESS;
GST_UNLOCK(queue);
}
return ret;
} }
@ -397,11 +502,11 @@ gst_queue_set_arg (GtkObject *object, GtkArg *arg, guint id)
queue = GST_QUEUE (object); queue = GST_QUEUE (object);
switch(id) { switch(id) {
case ARG_MAX_LEVEL: case ARG_LEAKY:
queue->max_buffers = GTK_VALUE_INT (*arg); queue->leaky = GTK_VALUE_INT (*arg);
break; break;
case ARG_BLOCK: case ARG_MAX_LEVEL:
queue->block = GTK_VALUE_BOOL (*arg); queue->size_buffers = GTK_VALUE_INT (*arg);
break; break;
default: default:
break; break;
@ -419,14 +524,14 @@ gst_queue_get_arg (GtkObject *object, GtkArg *arg, guint id)
queue = GST_QUEUE (object); queue = GST_QUEUE (object);
switch (id) { switch (id) {
case ARG_LEAKY:
GTK_VALUE_INT (*arg) = queue->leaky;
break;
case ARG_LEVEL: case ARG_LEVEL:
GTK_VALUE_INT (*arg) = queue->level_buffers; GTK_VALUE_INT (*arg) = queue->level_buffers;
break; break;
case ARG_MAX_LEVEL: case ARG_MAX_LEVEL:
GTK_VALUE_INT (*arg) = queue->max_buffers; GTK_VALUE_INT (*arg) = queue->size_buffers;
break;
case ARG_BLOCK:
GTK_VALUE_BOOL (*arg) = queue->block;
break; break;
default: default:
arg->type = GTK_TYPE_INVALID; arg->type = GTK_TYPE_INVALID;

View file

@ -47,6 +47,12 @@ GstElementDetails gst_queue_details;
#define GST_IS_QUEUE_CLASS(obj) \ #define GST_IS_QUEUE_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE)) (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
enum {
GST_QUEUE_NO_LEAK = 0,
GST_QUEUE_LEAK_UPSTREAM = 1,
GST_QUEUE_LEAK_DOWNSTREAM = 2
};
typedef struct _GstQueue GstQueue; typedef struct _GstQueue GstQueue;
typedef struct _GstQueueClass GstQueueClass; typedef struct _GstQueueClass GstQueueClass;
@ -60,12 +66,16 @@ struct _GstQueue {
GSList *queue; GSList *queue;
gint level_buffers; /* number of buffers queued here */ gint level_buffers; /* number of buffers queued here */
gint max_buffers; /* maximum number of buffers queued here */
gboolean block; /* if set to FALSE, _get returns NULL if queue empty */
gint level_bytes; /* number of bytes queued here */ gint level_bytes; /* number of bytes queued here */
guint64 level_time; /* amount of time queued here */
gint size_buffers; /* size of queue in buffers */ gint size_buffers; /* size of queue in buffers */
gint size_bytes; /* size of queue in bytes */ gint size_bytes; /* size of queue in bytes */
guint64 size_time; /* size of queue in time */
gint leaky; /* whether the queue is leaky, and if so at which end */
// GMutex *lock; (optimization?)
GCond *emptycond; GCond *emptycond;
GCond *fullcond; GCond *fullcond;
@ -74,6 +84,10 @@ struct _GstQueue {
struct _GstQueueClass { struct _GstQueueClass {
GstElementClass parent_class; GstElementClass parent_class;
/* signal callbacks */
void (*low_watermark) (GstQueue *queue, gint level);
void (*high_watermark) (GstQueue *queue, gint level);
}; };
GtkType gst_queue_get_type (void); GtkType gst_queue_get_type (void);

File diff suppressed because it is too large Load diff

View file

@ -24,6 +24,7 @@
#ifndef __GST_SCHEDULER_H__ #ifndef __GST_SCHEDULER_H__
#define __GST_SCHEDULER_H__ #define __GST_SCHEDULER_H__
#include <gst/gstelement.h>
#include <gst/gstbin.h> #include <gst/gstbin.h>
@ -32,8 +33,106 @@ extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
#define GST_TYPE_SCHEDULE \
(gst_schedule_get_type())
#define GST_SCHEDULE(obj) \
(GTK_CHECK_CAST((obj),GST_TYPE_SCHEDULE,GstSchedule))
#define GST_SCHEDULE_CLASS(klass) \
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_SCHEDULE,GstScheduleClass))
#define GST_IS_SCHEDULE(obj) \
(GTK_CHECK_TYPE((obj),GST_TYPE_SCHEDULE))
#define GST_IS_SCHEDULE_CLASS(klass) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_SCHEDULE))
#define GST_SCHED_PARENT(sched) ((sched)->parent)
//typedef struct _GstSchedule GstSchedule;
//typedef struct _GstScheduleClass GstScheduleClass;
typedef struct _GstScheduleChain GstScheduleChain;
struct _GstSchedule {
GstObject object;
GstElement *parent;
GList *elements;
gint num_elements;
GList *chains;
gint num_chains;
void (*add_element) (GstSchedule *sched, GstElement *element);
void (*remove_element) (GstSchedule *sched, GstElement *element);
void (*enable_element) (GstSchedule *sched, GstElement *element);
void (*disable_element) (GstSchedule *sched, GstElement *element);
void (*lock_element) (GstSchedule *sched, GstElement *element);
void (*unlock_element) (GstSchedule *sched, GstElement *element);
void (*pad_connect) (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
void (*pad_disconnect) (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
gboolean (*iterate) (GstSchedule *sched);
};
struct _GstScheduleClass {
GstObjectClass parent_class;
};
//#define GST_SCHEDULE_SAFETY if (sched)
#define GST_SCHEDULE_SAFETY
#define GST_SCHEDULE_ADD_ELEMENT(sched,element) \
GST_SCHEDULE_SAFETY ((sched)->add_element((sched),(element)))
#define GST_SCHEDULE_REMOVE_ELEMENT(sched,element) \
GST_SCHEDULE_SAFETY ((sched)->remove_element((sched),(element)))
#define GST_SCHEDULE_ENABLE_ELEMENT(sched,element) \
GST_SCHEDULE_SAFETY ((sched)->enable_element((sched),(element)))
#define GST_SCHEDULE_DISABLE_ELEMENT(sched,element) \
GST_SCHEDULE_SAFETY ((sched)->disable_element((sched),(element)))
#define GST_SCHEDULE_LOCK_ELEMENT(sched,element) \
GST_SCHEDULE_SAFETY if ((sched)->lock_element != NULL) \
((sched)->lock_element((sched),(element)))
#define GST_SCHEDULE_UNLOCK_ELEMENT(sched,element) \
GST_SCHEDULE_SAFETY if ((sched)->unlock_element != NULL) \
((sched)->unlock_element((sched),(element)))
#define GST_SCHEDULE_PAD_CONNECT(sched,srcpad,sinkpad) \
GST_SCHEDULE_SAFETY ((sched)->pad_connect((sched),(srcpad),(sinkpad)))
#define GST_SCHEDULE_PAD_DISCONNECT(sched,srcpad,sinkpad) \
GST_SCHEDULE_SAFETY ((sched)->pad_disconnect((sched),(srcpad),(sinkpad)))
#define GST_SCHEDULE_ITERATE(sched) \
((sched)->iterate((sched)))
struct _GstScheduleChain {
GstSchedule *sched;
GList *disabled;
GList *elements;
gint num_elements;
GstElement *entry;
gint cothreaded_elements;
gboolean schedule;
};
void gst_bin_schedule_func(GstBin *bin); void gst_bin_schedule_func(GstBin *bin);
GtkType gst_schedule_get_type (void);
GstSchedule * gst_schedule_new (GstElement *parent);
void gst_schedule_add_element (GstSchedule *sched, GstElement *element);
void gst_schedule_remove_element (GstSchedule *sched, GstElement *element);
void gst_schedule_enable_element (GstSchedule *sched, GstElement *element);
void gst_schedule_disable_element (GstSchedule *sched, GstElement *element);
void gst_schedule_pad_connect (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
void gst_schedule_pad_disconnect (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
gboolean gst_schedule_iterate (GstSchedule *sched);
void gst_schedule_show (GstSchedule *sched);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -26,7 +26,8 @@
#include "gst_private.h" #include "gst_private.h"
#include "gstthread.h" #include "gstthread.h"
#include "gstscheduler.h"
#include "gstqueue.h"
GstElementDetails gst_thread_details = { GstElementDetails gst_thread_details = {
"Threaded container", "Threaded container",
@ -44,15 +45,24 @@ enum {
LAST_SIGNAL LAST_SIGNAL
}; };
enum {
SPINUP=0,
STATECHANGE,
STARTUP
};
enum { enum {
ARG_0, ARG_0,
ARG_CREATE_THREAD, ARG_CREATE_THREAD,
}; };
static void gst_thread_class_init (GstThreadClass *klass); static void gst_thread_class_init (GstThreadClass *klass);
static void gst_thread_init (GstThread *thread); static void gst_thread_init (GstThread *thread);
static void gst_thread_real_destroy (GtkObject *gtk_object);
static void gst_thread_set_arg (GtkObject *object, GtkArg *arg, guint id); static void gst_thread_set_arg (GtkObject *object, GtkArg *arg, guint id);
static void gst_thread_get_arg (GtkObject *object, GtkArg *arg, guint id); static void gst_thread_get_arg (GtkObject *object, GtkArg *arg, guint id);
@ -61,9 +71,7 @@ static GstElementStateReturn gst_thread_change_state (GstElement *element);
static xmlNodePtr gst_thread_save_thyself (GstObject *object, xmlNodePtr parent); static xmlNodePtr gst_thread_save_thyself (GstObject *object, xmlNodePtr parent);
static void gst_thread_restore_thyself (GstObject *object, xmlNodePtr self); static void gst_thread_restore_thyself (GstObject *object, xmlNodePtr self);
static void gst_thread_signal_thread (GstThread *thread); static void gst_thread_signal_thread (GstThread *thread, gboolean spinning);
static void gst_thread_wait_thread (GstThread *thread);
static void gst_thread_schedule_dummy (GstBin *bin);
static void* gst_thread_main_loop (void *arg); static void* gst_thread_main_loop (void *arg);
@ -108,12 +116,14 @@ gst_thread_class_init (GstThreadClass *klass)
gtk_object_add_arg_type ("GstThread::create_thread", GTK_TYPE_BOOL, gtk_object_add_arg_type ("GstThread::create_thread", GTK_TYPE_BOOL,
GTK_ARG_READWRITE, ARG_CREATE_THREAD); GTK_ARG_READWRITE, ARG_CREATE_THREAD);
gtkobject_class->destroy = gst_thread_real_destroy;
gstobject_class->save_thyself = gst_thread_save_thyself; gstobject_class->save_thyself = gst_thread_save_thyself;
gstobject_class->restore_thyself = gst_thread_restore_thyself; gstobject_class->restore_thyself = gst_thread_restore_thyself;
gstelement_class->change_state = gst_thread_change_state; gstelement_class->change_state = gst_thread_change_state;
gstbin_class->schedule = gst_thread_schedule_dummy; // gstbin_class->schedule = gst_thread_schedule_dummy;
gtkobject_class->set_arg = gst_thread_set_arg; gtkobject_class->set_arg = gst_thread_set_arg;
gtkobject_class->get_arg = gst_thread_get_arg; gtkobject_class->get_arg = gst_thread_get_arg;
@ -123,26 +133,41 @@ gst_thread_class_init (GstThreadClass *klass)
static void static void
gst_thread_init (GstThread *thread) gst_thread_init (GstThread *thread)
{ {
GST_DEBUG (0,"initializing thread '%s'\n",GST_ELEMENT_NAME (thread));
GST_DEBUG (GST_CAT_THREAD,"initializing thread\n");
// we're a manager by default // we're a manager by default
GST_FLAG_SET (thread, GST_BIN_FLAG_MANAGER); GST_FLAG_SET (thread, GST_BIN_FLAG_MANAGER);
// default is to create a thread // default is to create a thread
GST_FLAG_SET (thread, GST_THREAD_CREATE); GST_FLAG_SET (thread, GST_THREAD_CREATE);
GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
thread->lock = g_mutex_new(); thread->lock = g_mutex_new();
thread->cond = g_cond_new(); thread->cond = g_cond_new();
GST_ELEMENT_SCHED(thread) = gst_schedule_new(GST_ELEMENT(thread));
GST_DEBUG(GST_CAT_THREAD, "thread's scheduler is %p\n",GST_ELEMENT_SCHED(thread));
thread->ppid = getpid();
// gst_element_set_manager(GST_ELEMENT(thread),GST_ELEMENT(thread));
} }
static void static void
gst_thread_schedule_dummy (GstBin *bin) gst_thread_real_destroy (GtkObject *gtk_object)
{ {
g_return_if_fail (GST_IS_THREAD (bin)); GstThread *thread = GST_THREAD (gtk_object);
if (!GST_FLAG_IS_SET (GST_THREAD (bin), GST_THREAD_STATE_SPINNING)) GST_DEBUG (GST_CAT_REFCOUNTING,"destroy()\n");
GST_INFO (GST_CAT_THREAD,"gstthread: scheduling delayed until thread starts");
g_mutex_free (thread->lock);
g_cond_free (thread->cond);
if (GTK_OBJECT_CLASS (parent_class)->destroy)
GTK_OBJECT_CLASS (parent_class)->destroy (gtk_object);
gst_object_destroy (GST_OBJECT (GST_ELEMENT_SCHED (thread)));
gst_object_unref (GST_OBJECT (GST_ELEMENT_SCHED (thread)));
} }
static void static void
@ -156,13 +181,13 @@ gst_thread_set_arg (GtkObject *object,
switch(id) { switch(id) {
case ARG_CREATE_THREAD: case ARG_CREATE_THREAD:
if (GTK_VALUE_BOOL (*arg)) { if (GTK_VALUE_BOOL (*arg)) {
GST_INFO (GST_CAT_THREAD,"gstthread: turning ON the creation of the thread"); GST_INFO (GST_CAT_THREAD,"turning ON the creation of the thread");
GST_FLAG_SET (object, GST_THREAD_CREATE); GST_FLAG_SET (object, GST_THREAD_CREATE);
GST_DEBUG (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object)); // GST_DEBUG (GST_CAT_THREAD,"flags are 0x%08x\n", GST_FLAGS (object));
} else { } else {
GST_INFO (GST_CAT_THREAD,"gstthread: turning OFF the creation of the thread"); GST_INFO (GST_CAT_THREAD,"gstthread: turning OFF the creation of the thread");
GST_FLAG_UNSET (object, GST_THREAD_CREATE); GST_FLAG_UNSET (object, GST_THREAD_CREATE);
GST_DEBUG (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object)); // GST_DEBUG (GST_CAT_THREAD,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
} }
break; break;
default: default:
@ -197,95 +222,237 @@ gst_thread_get_arg (GtkObject *object,
* Returns: The new thread * Returns: The new thread
*/ */
GstElement* GstElement*
gst_thread_new (guchar *name) gst_thread_new (const guchar *name)
{ {
return gst_elementfactory_make ("thread", name); return gst_elementfactory_make ("thread", name);
} }
#define THR_INFO(format,args...) \
GST_INFO_ELEMENT(GST_CAT_THREAD, thread, "sync(" GST_DEBUG_THREAD_FORMAT "): " format , \
GST_DEBUG_THREAD_ARGS(thread->pid) , ## args )
#define THR_DEBUG(format,args...) \
GST_DEBUG_ELEMENT(GST_CAT_THREAD, thread, "sync(" GST_DEBUG_THREAD_FORMAT "): " format , \
GST_DEBUG_THREAD_ARGS(thread->pid) , ## args )
#define THR_INFO_MAIN(format,args...) \
GST_INFO_ELEMENT(GST_CAT_THREAD, thread, "sync-main(" GST_DEBUG_THREAD_FORMAT "): " format , \
GST_DEBUG_THREAD_ARGS(thread->ppid) , ## args )
#define THR_DEBUG_MAIN(format,args...) \
GST_DEBUG_ELEMENT(GST_CAT_THREAD, thread, "sync-main(" GST_DEBUG_THREAD_FORMAT "): " format , \
GST_DEBUG_THREAD_ARGS(thread->ppid) , ## args )
static GstElementStateReturn static GstElementStateReturn
gst_thread_change_state (GstElement *element) gst_thread_change_state (GstElement *element)
{ {
GstThread *thread; GstThread *thread;
gboolean stateset = GST_STATE_SUCCESS; gboolean stateset = GST_STATE_SUCCESS;
gint pending, transition; gint transition;
pthread_t self = pthread_self();
GstElement *peerelement;
g_return_val_if_fail (GST_IS_THREAD(element), FALSE); g_return_val_if_fail (GST_IS_THREAD(element), FALSE);
GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME(element)); // GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME(element));
thread = GST_THREAD (element); thread = GST_THREAD (element);
// GST_DEBUG (GST_CAT_THREAD, "**** THREAD %ld changing THREAD %ld ****\n",self,thread->thread_id);
// GST_DEBUG (GST_CAT_THREAD, "**** current pid=%d\n",getpid());
GST_INFO (GST_CAT_THREAD,"gstthread: thread \"%s\" change state %d",
GST_ELEMENT_NAME (GST_ELEMENT (element)),
GST_STATE_PENDING (element));
pending = GST_STATE_PENDING (element);
transition = GST_STATE_TRANSITION (element); transition = GST_STATE_TRANSITION (element);
// if (pending == GST_STATE (element)) return GST_STATE_SUCCESS; THR_INFO("changing state from %s to %s",
gst_element_statename(GST_STATE (element)),
gst_element_statename(GST_STATE_PENDING (element)));
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING); //GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
if (GST_ELEMENT_CLASS (parent_class)->change_state)
stateset = GST_ELEMENT_CLASS (parent_class)->change_state (element);
GST_INFO (GST_CAT_THREAD, "gstthread: stateset %d %d %d %02x", GST_STATE (element), stateset,
GST_STATE_PENDING (element), GST_STATE_TRANSITION (element));
switch (transition) { switch (transition) {
case GST_STATE_NULL_TO_READY: case GST_STATE_NULL_TO_READY:
// if (!stateset) return FALSE;
// we want to prepare our internal state for doing the iterations
GST_INFO (GST_CAT_THREAD, "gstthread: preparing thread \"%s\" for iterations:",
GST_ELEMENT_NAME (GST_ELEMENT (element)));
// set the state to idle // set the state to idle
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING); GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
// create the thread if that's what we're supposed to do GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
GST_INFO (GST_CAT_THREAD, "gstthread: flags are 0x%08x", GST_FLAGS (thread));
// create the thread if that's what we're supposed to do
if (GST_FLAG_IS_SET (thread, GST_THREAD_CREATE)) { if (GST_FLAG_IS_SET (thread, GST_THREAD_CREATE)) {
GST_INFO (GST_CAT_THREAD, "gstthread: starting thread \"%s\"", THR_DEBUG ("creating thread \"%s\"\n",
GST_ELEMENT_NAME (GST_ELEMENT (element))); GST_ELEMENT_NAME (element));
g_mutex_lock (thread->lock); g_mutex_lock (thread->lock);
// create the thread // create the thread
pthread_create (&thread->thread_id, NULL, pthread_create (&thread->thread_id, NULL,
gst_thread_main_loop, thread); gst_thread_main_loop, thread);
// wait for it to 'spin up' // wait for it to 'spin up'
//gst_thread_wait_thread (thread); THR_DEBUG("waiting for child thread spinup\n");
g_cond_wait (thread->cond, thread->lock); g_cond_wait(thread->cond,thread->lock);
g_mutex_unlock (thread->lock); THR_DEBUG("thread claims to be up\n");
g_mutex_unlock(thread->lock);
} else { } else {
GST_INFO (GST_CAT_THREAD, "gstthread: NOT starting thread \"%s\"", GST_INFO (GST_CAT_THREAD, "NOT creating thread \"%s\"",
GST_ELEMENT_NAME (GST_ELEMENT (element))); 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; break;
case GST_STATE_PAUSED_TO_PLAYING: case GST_STATE_PAUSED_TO_PLAYING:
case GST_STATE_READY_TO_PLAYING: THR_INFO("starting thread");
if (!stateset) return FALSE;
GST_INFO (GST_CAT_THREAD, "gstthread: starting thread \"%s\"",
GST_ELEMENT_NAME (GST_ELEMENT (element)));
GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING); // check to see if the thread is somehow changing its own state.
gst_thread_signal_thread (thread); // 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; break;
case GST_STATE_PLAYING_TO_PAUSED: case GST_STATE_PLAYING_TO_PAUSED:
GST_INFO (GST_CAT_THREAD,"gstthread: pausing thread \"%s\"", THR_INFO("pausing thread");
GST_ELEMENT_NAME (GST_ELEMENT (element)));
//GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING); // check to see if the thread is somehow changing its own state.
gst_thread_signal_thread (thread); // FIXME this is currently illegal, but must somehow be made legal at some point.
if (pthread_equal(self, thread->thread_id))
{
//FIXME this should not happen
GST_DEBUG(GST_CAT_THREAD,"no sync(" GST_DEBUG_THREAD_FORMAT "): setting own thread's state to paused\n",
GST_DEBUG_THREAD_ARGS(thread->pid));
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
g_assert(!pthread_equal(self, thread->thread_id));
}
else
{
GList *elements = (element->sched)->elements;
// the following code ensures that the bottom half of thread will run
// to perform each elements' change_state() (by calling gstbin.c::
// change_state()).
// + the pending state was already set by gstelement.c::set_state()
// + find every queue we manage, and signal its empty and full conditions
g_mutex_lock(thread->lock);
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
while (elements)
{
GstElement *e = GST_ELEMENT(elements->data);
g_assert(e);
THR_DEBUG(" element \"%s\"\n",GST_ELEMENT_NAME(e));
elements = g_list_next(elements);
if (GST_IS_QUEUE(e))
{
//FIXME make this more efficient by only waking queues that are asleep
//FIXME and only waking the appropriate condition (depending on if it's
//FIXME on up- or down-stream side)
//
//FIXME also make this more efficient by keeping list of managed queues
THR_DEBUG("waking queue \"%s\"\n",GST_ELEMENT_NAME(e));
GST_LOCK(e);
g_cond_signal((GST_QUEUE(e)->emptycond));
g_cond_signal((GST_QUEUE(e)->fullcond));
GST_UNLOCK(e);
}
else
{
GList *pads = GST_ELEMENT_PADS(e);
while (pads)
{
GstPad *p = GST_PAD(pads->data);
pads = g_list_next(pads);
peerelement = GST_PAD_PARENT(GST_PAD_PEER(p));
if (!peerelement) continue; // deal with case where there's no peer
if (!GST_FLAG_IS_SET(peerelement,GST_ELEMENT_DECOUPLED)) {
GST_DEBUG(GST_CAT_THREAD,"peer element isn't DECOUPLED\n");
continue;
}
// FIXME this needs to go away eventually
if (!GST_IS_QUEUE(peerelement)) {
GST_DEBUG(GST_CAT_THREAD,"peer element isn't a Queue\n");
continue;
}
if (GST_ELEMENT_SCHED(peerelement) != GST_ELEMENT_SCHED(thread))
{
THR_DEBUG(" element \"%s\" has pad cross sched boundary\n",GST_ELEMENT_NAME(e));
GST_LOCK(peerelement);
g_cond_signal(GST_QUEUE(peerelement)->emptycond);
g_cond_signal(GST_QUEUE(peerelement)->fullcond);
GST_UNLOCK(peerelement);
}
}
}
}
THR_DEBUG("waiting for thread to stop spinning\n");
g_cond_wait (thread->cond, thread->lock);
THR_DEBUG("telling thread to pause\n");
gst_thread_signal_thread(thread,FALSE);
}
break; break;
case GST_STATE_READY_TO_NULL: case GST_STATE_READY_TO_NULL:
GST_INFO (GST_CAT_THREAD,"gstthread: stopping thread \"%s\"", THR_INFO("stopping thread");
GST_ELEMENT_NAME (GST_ELEMENT (element)));
GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING); GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
gst_thread_signal_thread (thread);
pthread_join(thread->thread_id,NULL); // check to see if the thread is somehow changing its own state.
// FIXME this is currently illegal, but must somehow be made legal at some point.
if (pthread_equal(self, thread->thread_id))
{
//FIXME this should not happen
g_assert(!pthread_equal(self, thread->thread_id));
THR_DEBUG("setting own thread's state to NULL (paused)\n");
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
}
else
{
THR_DEBUG("telling thread to pause (null) - and joining\n");
//MattH FIXME revisit
// g_mutex_lock(thread->lock);
// gst_thread_signal_thread(thread,FALSE);
pthread_join(thread->thread_id,NULL);
}
GST_FLAG_UNSET(thread,GST_THREAD_STATE_REAPING);
GST_FLAG_UNSET(thread,GST_THREAD_STATE_STARTED);
GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
GST_FLAG_UNSET(thread,GST_THREAD_STATE_ELEMENT_CHANGED);
if (GST_ELEMENT_CLASS (parent_class)->change_state)
stateset = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
break; break;
default: default:
break; break;
@ -294,6 +461,16 @@ gst_thread_change_state (GstElement *element)
return stateset; return stateset;
} }
static void gst_thread_update_state (GstThread *thread)
{
// check for state change
if (GST_STATE_PENDING(thread) != GST_STATE_NONE_PENDING) {
// punt and change state on all the children
if (GST_ELEMENT_CLASS (parent_class)->change_state)
GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
}
}
/** /**
* gst_thread_main_loop: * gst_thread_main_loop:
* @arg: the thread to start * @arg: the thread to start
@ -305,53 +482,186 @@ static void *
gst_thread_main_loop (void *arg) gst_thread_main_loop (void *arg)
{ {
GstThread *thread = GST_THREAD (arg); GstThread *thread = GST_THREAD (arg);
gint stateset;
GST_INFO (GST_CAT_THREAD,"gstthread: thread \"%s\" is running with PID %d", thread->pid = getpid();
GST_ELEMENT_NAME (GST_ELEMENT (thread)), 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)
stateset = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
// construct the plan and signal back // construct the plan and signal back
/* DEPRACATED for INCSCHED1
THR_DEBUG_MAIN("creating plan for thread\n");
if (GST_BIN_CLASS (parent_class)->schedule) if (GST_BIN_CLASS (parent_class)->schedule)
GST_BIN_CLASS (parent_class)->schedule (GST_BIN (thread)); GST_BIN_CLASS (parent_class)->schedule (GST_BIN (thread));
*/
gst_thread_signal_thread (thread); // THR_DEBUG_MAIN("indicating spinup\n");
g_mutex_lock (thread->lock);
g_cond_signal (thread->cond);
// don't unlock the mutex because we hold it into the top of the while loop
THR_DEBUG_MAIN("thread has indicated spinup to parent process\n");
/***** THREAD IS NOW IN READY STATE *****/
while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) { while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) {
if (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) { // NOTE we hold the thread lock at this point
if (!gst_bin_iterate (GST_BIN (thread))) { // what we do depends on what state we're in
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING); switch (GST_STATE(thread)) {
} // NOTE: cannot be in NULL, we're not running in that state at all
} case GST_STATE_READY:
else { // wait to be set to either the NULL or PAUSED states
GST_DEBUG (0, "thread \"%s\" waiting\n", GST_ELEMENT_NAME (GST_ELEMENT (thread))); THR_DEBUG_MAIN("thread in %s state, waiting for either %s or %s\n",
gst_thread_wait_thread (thread); gst_element_statename(GST_STATE_READY),
gst_element_statename(GST_STATE_NULL),
gst_element_statename(GST_STATE_PAUSED));
g_cond_wait(thread->cond,thread->lock);
// been signaled, we need to state transition now and signal back
gst_thread_update_state(thread);
THR_DEBUG_MAIN("done with state transition, signaling back to parent process\n");
g_cond_signal(thread->cond);
// g_mutex_unlock(thread->lock);
// now we decide what to do next (FIXME can be collapsed to a continue)
if (GST_STATE(thread) == GST_STATE_NULL) {
// REAPING must be set, we can simply break this iteration
continue;
} else {
// PAUSED is the next state, we can wait for that next
continue;
}
break;
case GST_STATE_PAUSED:
// wait to be set to either the READY or PLAYING states
THR_DEBUG_MAIN("thread in %s state, waiting for either %s or %s\n",
gst_element_statename(GST_STATE_PAUSED),
gst_element_statename(GST_STATE_READY),
gst_element_statename(GST_STATE_PLAYING));
g_cond_wait(thread->cond,thread->lock);
// been signaled, we need to state transition now and signal back
gst_thread_update_state(thread);
g_cond_signal(thread->cond);
// g_mutex_unlock(thread->lock);
// now we decide what to do next
if (GST_STATE(thread) == GST_STATE_READY) {
// READY is the next state, we can wait for that next
continue;
} else {
g_mutex_unlock(thread->lock);
// PLAYING is coming up, so we can now start spinning
while (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
if (!gst_bin_iterate (GST_BIN (thread))) {
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
THR_DEBUG_MAIN("removed spinning state due to failed iteration!\n");
}
}
g_mutex_lock(thread->lock);
// once we're here, SPINNING has stopped, we should signal that we're done
THR_DEBUG_MAIN("SPINNING stopped, signaling back to parent process\n");
g_cond_signal (thread->cond);
// now we can wait for PAUSED
continue;
}
break;
case GST_STATE_PLAYING:
// wait to be set to PAUSED
THR_DEBUG_MAIN("thread in %s state, waiting for %s\n",
gst_element_statename(GST_STATE_PLAYING),
gst_element_statename(GST_STATE_PAUSED));
g_cond_wait(thread->cond,thread->lock);
// been signaled, we need to state transition now and signal back
gst_thread_update_state(thread);
g_cond_signal(thread->cond);
// g_mutex_unlock(thread->lock);
// now we decide what to do next
// there's only PAUSED, we we just wait for it
continue;
break;
} }
// need to grab the lock so we're ready for the top of the loop
// g_mutex_lock(thread->lock);
} }
GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING); /*
// FIXME this should be removed (why's it here???) while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) {
// //pthread_join (thread->thread_id, 0); // 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);
GST_INFO (GST_CAT_THREAD, "gstthread: thread \"%s\" is stopped", GST_INFO (GST_CAT_THREAD, "gstthread: thread \"%s\" is stopped",
GST_ELEMENT_NAME (thread)); GST_ELEMENT_NAME (thread));
return NULL; 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 static void
gst_thread_signal_thread (GstThread *thread) gst_thread_signal_thread (GstThread *thread, gboolean spinning)
{ {
GST_DEBUG (0,"signaling thread\n"); // set the spinning state
g_mutex_lock (thread->lock); if (spinning) GST_FLAG_SET(thread,GST_THREAD_STATE_SPINNING);
g_cond_signal (thread->cond); else GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
g_mutex_unlock (thread->lock);
}
static void THR_DEBUG("thread locked\n");
gst_thread_wait_thread (GstThread *thread) // g_mutex_lock(thread->lock);
{
GST_DEBUG (0,"waiting for thread\n"); // if (!spinning) {
g_mutex_lock (thread->lock); // THR_DEBUG("waiting for spindown\n");
g_cond_wait (thread->cond, thread->lock); // g_cond_wait (thread->cond, thread->lock);
g_mutex_unlock (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");
} }
@ -359,7 +669,7 @@ static void
gst_thread_restore_thyself (GstObject *object, gst_thread_restore_thyself (GstObject *object,
xmlNodePtr self) xmlNodePtr self)
{ {
GST_DEBUG (0,"gstthread: restore\n"); GST_DEBUG (GST_CAT_THREAD,"gstthread: restore\n");
if (GST_OBJECT_CLASS (parent_class)->restore_thyself) if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
GST_OBJECT_CLASS (parent_class)->restore_thyself (object, self); GST_OBJECT_CLASS (parent_class)->restore_thyself (object, self);

View file

@ -24,6 +24,7 @@
#ifndef __GST_THREAD_H__ #ifndef __GST_THREAD_H__
#define __GST_THREAD_H__ #define __GST_THREAD_H__
#include <unistd.h>
#include <pthread.h> #include <pthread.h>
#include <gst/gstbin.h> #include <gst/gstbin.h>
@ -38,8 +39,11 @@ extern GstElementDetails gst_thread_details;
typedef enum { typedef enum {
GST_THREAD_CREATE = GST_BIN_FLAG_LAST, GST_THREAD_CREATE = GST_BIN_FLAG_LAST,
GST_THREAD_STATE_STARTED,
GST_THREAD_STATE_SPINNING, GST_THREAD_STATE_SPINNING,
GST_THREAD_STATE_REAPING, GST_THREAD_STATE_REAPING,
GST_THREAD_STATE_ELEMENT_CHANGED,
/* padding */ /* padding */
GST_THREAD_FLAG_LAST = GST_BIN_FLAG_LAST + 4, GST_THREAD_FLAG_LAST = GST_BIN_FLAG_LAST + 4,
@ -64,8 +68,12 @@ struct _GstThread {
GstBin bin; GstBin bin;
pthread_t thread_id; /* id of the thread, if any */ pthread_t thread_id; /* id of the thread, if any */
gint pid; /* the pid of the thread */
gint ppid; /* the pid of the thread's parent process */
GMutex *lock; /* thread lock/condititon pair... */ GMutex *lock; /* thread lock/condititon pair... */
GCond *cond; /* used to control the thread */ GCond *cond; /* used to control the thread */
gint transition; /* the current state transition */
}; };
struct _GstThreadClass { struct _GstThreadClass {
@ -74,7 +82,7 @@ struct _GstThreadClass {
GtkType gst_thread_get_type (void); GtkType gst_thread_get_type (void);
GstElement* gst_thread_new (guchar *name); GstElement* gst_thread_new (const guchar *name);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -80,7 +80,7 @@ gst_type_register (GstTypeFactory *factory)
_gst_types = g_list_prepend (_gst_types, type); _gst_types = g_list_prepend (_gst_types, type);
id = type->id; id = type->id;
GST_DEBUG (0,"gsttype: new mime type '%s', id %d\n", type->mime, type->id); GST_DEBUG (GST_CAT_TYPES,"gsttype: new mime type '%s', id %d\n", type->mime, type->id);
} else { } else {
type = gst_type_find_by_id (id); type = gst_type_find_by_id (id);
@ -108,12 +108,12 @@ guint16 gst_type_find_by_mime_func (const gchar *mime)
g_return_val_if_fail (mime != NULL, 0); g_return_val_if_fail (mime != NULL, 0);
walk = _gst_types; walk = _gst_types;
// GST_DEBUG (0,"searching for '%s'\n",mime); // GST_DEBUG (GST_CAT_TYPES,"searching for '%s'\n",mime);
mimelen = strlen (mime); mimelen = strlen (mime);
while (walk) { while (walk) {
type = (GstType *)walk->data; type = (GstType *)walk->data;
search = type->mime; search = type->mime;
// GST_DEBUG (0,"checking against '%s'\n",search); // GST_DEBUG (GST_CAT_TYPES,"checking against '%s'\n",search);
typelen = strlen (search); typelen = strlen (search);
while ((search - type->mime) < typelen) { while ((search - type->mime) < typelen) {
found = strstr (search, mime); found = strstr (search, mime);
@ -232,7 +232,7 @@ gst_type_typefind_dummy (GstBuffer *buffer, gpointer priv)
guint16 typeid; guint16 typeid;
GSList *funcs; GSList *funcs;
GST_DEBUG (0,"gsttype: need to load typefind function for %s\n", type->mime); GST_DEBUG (GST_CAT_TYPES,"gsttype: need to load typefind function for %s\n", type->mime);
type->typefindfuncs = NULL; type->typefindfuncs = NULL;
gst_plugin_load_typefactory (type->mime); gst_plugin_load_typefactory (type->mime);

View file

@ -180,11 +180,25 @@ gst_typefind_chain (GstPad *pad, GstBuffer *buf)
GST_DEBUG (0,"try type :%d \"%s\"\n", type->id, type->mime); GST_DEBUG (0,"try type :%d \"%s\"\n", type->id, type->mime);
if (typefindfunc && (caps = typefindfunc (buf, type))) { if (typefindfunc && (caps = typefindfunc (buf, type))) {
GST_DEBUG (0,"found type :%d \"%s\"\n", caps->id, type->mime); GST_DEBUG (0,"found type :%d \"%s\" \"%s\"\n", caps->id, type->mime,
gst_caps_get_name (caps));
typefind->caps = caps; typefind->caps = caps;
gst_pad_set_caps (pad, caps);
{ /* FIXME: this should all be in an _emit() wrapper eventually */
int oldstate = GST_STATE(typefind);
gst_object_ref (GST_OBJECT (typefind));
gtk_signal_emit (GTK_OBJECT (typefind), gst_typefind_signals[HAVE_TYPE], gtk_signal_emit (GTK_OBJECT (typefind), gst_typefind_signals[HAVE_TYPE],
typefind->caps); typefind->caps);
gst_pad_set_caps (pad, caps); if (GST_STATE(typefind) != oldstate) {
gst_object_unref (GST_OBJECT (typefind));
GST_DEBUG(0, "state changed during signal, aborting\n");
cothread_switch(cothread_current_main());
}
gst_object_unref (GST_OBJECT (typefind));
}
goto end; goto end;
} }
funcs = g_slist_next (funcs); funcs = g_slist_next (funcs);

17
gst/gsttypes.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef __GST_TYPES_H__
#define __GST_TYPES_H__
typedef struct _GstObject GstObject;
typedef struct _GstObjectClass GstObjectClass;
typedef struct _GstPad GstPad;
typedef struct _GstPadClass GstPadClass;
typedef struct _GstPadTemplate GstPadTemplate;
typedef struct _GstPadTemplateClass GstPadTemplateClass;
typedef struct _GstElement GstElement;
typedef struct _GstElementClass GstElementClass;
typedef struct _GstBin GstBin;
typedef struct _GstBinClass GstBinClass;
typedef struct _GstSchedule GstSchedule;
typedef struct _GstScheduleClass GstScheduleClass;
#endif

View file

@ -167,7 +167,7 @@ gst_xml_parse_doc (GstXML *xml, xmlDocPtr doc, const guchar *root)
if (!strcmp(field->name, "element") && (field->ns == xml->ns)) { if (!strcmp(field->name, "element") && (field->ns == xml->ns)) {
GstElement *element; GstElement *element;
element = gst_element_load_thyself(field, NULL); element = gst_element_restore_thyself(field, NULL);
xml->topelements = g_list_prepend (xml->topelements, element); xml->topelements = g_list_prepend (xml->topelements, element);
} }

View file

@ -37,6 +37,7 @@ noinst_HEADERS = \
gstplayprivate.h \ gstplayprivate.h \
full-screen.h full-screen.h
libgstmediaplay_la_LDFLAGS = -rdynamic libgstmediaplay_la_LDFLAGS = -rdynamic
gstmediaplay_CFLAGS = $(LIBGLADE_GNOME_CFLAGS) gstmediaplay_CFLAGS = $(LIBGLADE_GNOME_CFLAGS)

View file

@ -39,12 +39,11 @@ target_drag_data_received (GtkWidget *widget,
guint time, guint time,
GstMediaPlay *play) GstMediaPlay *play)
{ {
if (strstr (data->data, "file:")) { g_print ("Got: %s\n", data->data);
g_print ("Got: %s\n", &data->data[5]); gdk_threads_leave ();
gdk_threads_leave (); gst_media_play_start_uri (play, g_strchomp (data->data));
gst_media_play_start_uri (play, g_strchomp (&data->data[5])); gdk_threads_enter ();
gdk_threads_enter ();
}
} }
static GtkTargetEntry target_table[] = { static GtkTargetEntry target_table[] = {

View file

@ -508,6 +508,7 @@ Arik Devens &lt;arik@gnome.org&gt;
<last_modification_time>Sun, 06 Aug 2000 15:55:52 GMT</last_modification_time> <last_modification_time>Sun, 06 Aug 2000 15:55:52 GMT</last_modification_time>
</signal> </signal>
<stock_button>GNOME_STOCK_BUTTON_OK</stock_button> <stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
<relief>GTK_RELIEF_NORMAL</relief>
</widget> </widget>
<widget> <widget>
@ -523,6 +524,7 @@ Arik Devens &lt;arik@gnome.org&gt;
<last_modification_time>Sun, 06 Aug 2000 15:53:48 GMT</last_modification_time> <last_modification_time>Sun, 06 Aug 2000 15:53:48 GMT</last_modification_time>
</signal> </signal>
<stock_button>GNOME_STOCK_BUTTON_CANCEL</stock_button> <stock_button>GNOME_STOCK_BUTTON_CANCEL</stock_button>
<relief>GTK_RELIEF_NORMAL</relief>
</widget> </widget>
</widget> </widget>

View file

@ -1,20 +1,22 @@
#include <config.h> #include <config.h>
#include <string.h>
#include "gstplay.h" #include "gstplay.h"
#include "gstplayprivate.h" #include "gstplayprivate.h"
#include "full-screen.h" #include "full-screen.h"
static void gst_play_class_init (GstPlayClass *klass); static void gst_play_class_init (GstPlayClass *klass);
static void gst_play_init (GstPlay *play); static void gst_play_init (GstPlay *play);
static void gst_play_set_arg (GtkObject *object, GtkArg *arg, guint id); static void gst_play_set_arg (GtkObject *object, GtkArg *arg, guint id);
static void gst_play_get_arg (GtkObject *object, GtkArg *arg, guint id); static void gst_play_get_arg (GtkObject *object, GtkArg *arg, guint id);
static void gst_play_realize (GtkWidget *play); static void gst_play_realize (GtkWidget *play);
static void gst_play_frame_displayed (GstElement *element, GstPlay *play); static void gst_play_frame_displayed (GstElement *element, GstPlay *play);
static void gst_play_have_size (GstElement *element, guint width, guint height, GstPlay *play); static void gst_play_have_size (GstElement *element, guint width, guint height, GstPlay *play);
static void gst_play_audio_handoff (GstElement *element, GstPlay *play); static void gst_play_audio_handoff (GstElement *element, GstPlay *play);
/* signals and args */ /* signals and args */
enum { enum {
@ -118,10 +120,8 @@ gst_play_init (GstPlay *play)
play->priv = priv; play->priv = priv;
/* create a new bin to hold the elements */ /* create a new bin to hold the elements */
priv->thread = gst_thread_new ("main_thread"); priv->pipeline = gst_pipeline_new ("main_pipeline");
g_assert (priv->thread != NULL); g_assert (priv->pipeline != NULL);
priv->bin = gst_bin_new ("main_bin");
g_assert (priv->bin != NULL);
priv->audio_element = gst_elementfactory_make ("osssink", "play_audio"); priv->audio_element = gst_elementfactory_make ("osssink", "play_audio");
g_return_if_fail (priv->audio_element != NULL); g_return_if_fail (priv->audio_element != NULL);
@ -165,6 +165,12 @@ gst_play_new ()
return GST_PLAY (gtk_type_new (GST_TYPE_PLAY)); return GST_PLAY (gtk_type_new (GST_TYPE_PLAY));
} }
static gboolean
gst_play_idle_func (gpointer data)
{
return gst_bin_iterate (GST_BIN (data));
}
static void static void
gst_play_eos (GstElement *element, gst_play_eos (GstElement *element,
GstPlay *play) GstPlay *play)
@ -273,53 +279,68 @@ gst_play_object_added (GstAutoplug* autoplug, GstObject *object, GstPlay *play)
} }
static void static void
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data) gst_play_cache_empty (GstElement *element, GstPlay *play)
{ {
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data); GstPlayPrivate *priv;
GstElement *new_element;
*(gboolean *)data = TRUE; priv = (GstPlayPrivate *)play->priv;
gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
new_element = gst_bin_get_by_name (GST_BIN (priv->pipeline), "new_element");
gst_element_disconnect (priv->src, "src", priv->cache, "sink");
gst_element_disconnect (priv->cache, "src", new_element, "sink");
gst_bin_remove (GST_BIN (priv->pipeline), priv->cache);
gst_element_connect (priv->src, "src", new_element, "sink");
gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
} }
static GstCaps* static void
gst_play_typefind (GstBin *bin, GstElement *element) gst_play_have_type (GstElement *sink, GstCaps *caps, GstPlay *play)
{ {
gboolean found = FALSE; GstPlayPrivate *priv;
GstElement *typefind; GstElement *new_element;
GstCaps *caps = NULL; GstAutoplug *autoplug;
GST_DEBUG (0, "GstPipeline: typefind for element \"%s\" %p\n", GST_DEBUG (0,"GstPipeline: play have type\n");
GST_ELEMENT_NAME (element), &found);
typefind = gst_elementfactory_make ("typefind", "typefind"); priv = (GstPlayPrivate *)play->priv;
g_return_val_if_fail (typefind != NULL, FALSE);
gtk_signal_connect (GTK_OBJECT (typefind), "have_type", gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
gst_pad_connect (gst_element_get_pad (element, "src"), gst_element_disconnect (priv->cache, "src", priv->typefind, "sink");
gst_element_get_pad (typefind, "sink")); gst_bin_remove (GST_BIN (priv->pipeline), priv->typefind);
gst_bin_add (bin, typefind); autoplug = gst_autoplugfactory_make ("staticrender");
g_assert (autoplug != NULL);
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING); gtk_signal_connect (GTK_OBJECT (autoplug), "new_object", gst_play_object_added, play);
// push a buffer... the have_type signal handler will set the found flag new_element = gst_autoplug_to_renderers (autoplug,
gst_bin_iterate (bin); caps,
priv->video_element,
priv->audio_element,
NULL);
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL); if (!new_element) {
// FIXME, signal a suitable error
if (found) { return;
caps = gst_util_get_pointer_arg (GTK_OBJECT (typefind), "caps");
gst_pad_set_caps (gst_element_get_pad (element, "src"), caps);
} }
gst_pad_disconnect (gst_element_get_pad (element, "src"), gst_element_set_name (new_element, "new_element");
gst_element_get_pad (typefind, "sink"));
gst_bin_remove (bin, typefind);
gst_object_unref (GST_OBJECT (typefind));
return caps; gst_bin_add (GST_BIN (priv->pipeline), new_element);
gtk_object_set (GTK_OBJECT (priv->cache), "reset", TRUE, NULL);
gst_element_connect (priv->cache, "src", new_element, "sink");
gtk_signal_connect (GTK_OBJECT (priv->pipeline), "eos", GTK_SIGNAL_FUNC (gst_play_eos), play);
gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
} }
static gboolean static gboolean
@ -349,9 +370,7 @@ GstPlayReturn
gst_play_set_uri (GstPlay *play, const guchar *uri) gst_play_set_uri (GstPlay *play, const guchar *uri)
{ {
GstPlayPrivate *priv; GstPlayPrivate *priv;
GstCaps *src_caps; gchar* uriloc;
GstElement *new_element;
GstAutoplug *autoplug;
g_return_val_if_fail (play != NULL, GST_PLAY_ERROR); g_return_val_if_fail (play != NULL, GST_PLAY_ERROR);
g_return_val_if_fail (GST_IS_PLAY (play), GST_PLAY_ERROR); g_return_val_if_fail (GST_IS_PLAY (play), GST_PLAY_ERROR);
@ -362,47 +381,51 @@ gst_play_set_uri (GstPlay *play, const guchar *uri)
if (priv->uri) if (priv->uri)
g_free (priv->uri); g_free (priv->uri);
/* see if it looks like a ARI */
if ((uriloc = strstr (uri, ":/"))) {
priv->src = gst_elementfactory_make ("gnomevfssrc", "srcelement");
if (!priv->src) {
if (strstr (uri, "file:/")) {
uri += strlen ("file:/");
}
else
return GST_PLAY_CANNOT_PLAY;
}
}
if (priv->src == NULL) {
priv->src = gst_elementfactory_make ("disksrc", "srcelement");
}
priv->uri = g_strdup (uri); priv->uri = g_strdup (uri);
priv->src = gst_elementfactory_make ("disksrc", "disk_src");
//priv->src = gst_elementfactory_make ("dvdsrc", "disk_src"); //priv->src = gst_elementfactory_make ("dvdsrc", "disk_src");
priv->offset_element = priv->src; priv->offset_element = priv->src;
g_return_val_if_fail (priv->src != NULL, GST_PLAY_CANNOT_PLAY);
g_return_val_if_fail (priv->src != NULL, -1); gtk_object_set (GTK_OBJECT (priv->src), "location", priv->uri, NULL);
gtk_object_set (GTK_OBJECT (priv->src), "location", uri, NULL);
gst_bin_add (GST_BIN (priv->bin), priv->src);
src_caps = gst_play_typefind (GST_BIN (priv->bin), priv->src); priv->cache = gst_elementfactory_make ("autoplugcache", "cache");
g_return_val_if_fail (priv->cache != NULL, GST_PLAY_CANNOT_PLAY);
if (!src_caps) { gtk_signal_connect (GTK_OBJECT (priv->cache), "cache_empty",
return GST_PLAY_UNKNOWN_MEDIA; GTK_SIGNAL_FUNC (gst_play_cache_empty), play);
}
autoplug = gst_autoplugfactory_make ("staticrender"); priv->typefind = gst_elementfactory_make ("typefind", "typefind");
g_assert (autoplug != NULL); g_return_val_if_fail (priv->typefind != NULL, GST_PLAY_CANNOT_PLAY);
gtk_signal_connect (GTK_OBJECT (priv->typefind), "have_type",
GTK_SIGNAL_FUNC (gst_play_have_type), play);
gtk_signal_connect (GTK_OBJECT (autoplug), "new_object", gst_play_object_added, play);
new_element = gst_autoplug_to_renderers (autoplug, gst_bin_add (GST_BIN (priv->pipeline), priv->src);
gst_pad_get_caps (gst_element_get_pad (priv->src, "src")), gst_bin_add (GST_BIN (priv->pipeline), priv->cache);
priv->video_element, gst_bin_add (GST_BIN (priv->pipeline), priv->typefind);
priv->audio_element,
NULL);
if (!new_element) { gst_element_connect (priv->src, "src", priv->cache, "sink");
return GST_PLAY_CANNOT_PLAY; gst_element_connect (priv->cache, "src", priv->typefind, "sink");
}
gst_bin_remove (GST_BIN (priv->bin), priv->src);
gst_bin_add (GST_BIN (priv->thread), priv->src);
gst_bin_add (GST_BIN (priv->bin), new_element);
gst_element_connect (priv->src, "src", new_element, "sink");
gst_bin_add (GST_BIN (priv->thread), priv->bin);
gtk_signal_connect (GTK_OBJECT (priv->thread), "eos", GTK_SIGNAL_FUNC (gst_play_eos), play);
return GST_PLAY_OK; return GST_PLAY_OK;
} }
@ -449,10 +472,11 @@ gst_play_play (GstPlay *play)
if (play->state == GST_PLAY_PLAYING) return; if (play->state == GST_PLAY_PLAYING) return;
if (play->state == GST_PLAY_STOPPED) if (play->state == GST_PLAY_STOPPED)
gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_READY); gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_READY);
gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_PLAYING); gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_PLAYING);
play->state = GST_PLAY_PLAYING; play->state = GST_PLAY_PLAYING;
gtk_idle_add (gst_play_idle_func, priv->pipeline);
gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED], gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
play->state); play->state);
@ -470,9 +494,10 @@ gst_play_pause (GstPlay *play)
if (play->state != GST_PLAY_PLAYING) return; if (play->state != GST_PLAY_PLAYING) return;
gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_PAUSED); gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_PAUSED);
play->state = GST_PLAY_PAUSED; play->state = GST_PLAY_PAUSED;
g_idle_remove_by_data (priv->pipeline);
gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED], gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
play->state); play->state);
@ -491,11 +516,12 @@ gst_play_stop (GstPlay *play)
priv = (GstPlayPrivate *)play->priv; priv = (GstPlayPrivate *)play->priv;
// FIXME until state changes are handled properly // FIXME until state changes are handled properly
gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_READY); gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_READY);
gtk_object_set (GTK_OBJECT (priv->src),"offset",0,NULL); gtk_object_set (GTK_OBJECT (priv->src),"offset",0,NULL);
//gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_NULL); //gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_NULL);
play->state = GST_PLAY_STOPPED; play->state = GST_PLAY_STOPPED;
g_idle_remove_by_data (priv->pipeline);
gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED], gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
play->state); play->state);
@ -653,7 +679,7 @@ gst_play_get_pipeline (GstPlay *play)
priv = (GstPlayPrivate *)play->priv; priv = (GstPlayPrivate *)play->priv;
return GST_ELEMENT (priv->bin); return GST_ELEMENT (priv->pipeline);
} }
static void static void

View file

@ -19,10 +19,10 @@ typedef enum {
} GstPlayState; } GstPlayState;
typedef enum { typedef enum {
GST_PLAY_OK, GST_PLAY_OK,
GST_PLAY_UNKNOWN_MEDIA, GST_PLAY_UNKNOWN_MEDIA,
GST_PLAY_CANNOT_PLAY, GST_PLAY_CANNOT_PLAY,
GST_PLAY_ERROR, GST_PLAY_ERROR,
} GstPlayReturn; } GstPlayReturn;
typedef enum { typedef enum {

View file

@ -6,12 +6,13 @@
typedef struct _GstPlayPrivate GstPlayPrivate; typedef struct _GstPlayPrivate GstPlayPrivate;
struct _GstPlayPrivate { struct _GstPlayPrivate {
GstElement *thread; GstElement *pipeline;
GstElement *bin;
GstElement *video_element, *audio_element; GstElement *video_element, *audio_element;
GstElement *video_show; GstElement *video_show;
GtkWidget *video_widget; GtkWidget *video_widget;
GstElement *src; GstElement *src;
GstElement *cache;
GstElement *typefind;
guchar *uri; guchar *uri;
gboolean muted; gboolean muted;

View file

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: GStreamer Uninstalled
Description: Streaming-media framework, Not Installed
Version: @VERSION@
Requires: glib gtk+
Libs: ${pcbuilddir}/${pcfiledir}/gst/libgst.la
Cflags: -I${pcbuilddir}/${pcfiledir}

11
gstreamer.pc.in Normal file
View file

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: GStreamer
Description: Streaming-media framework
Requires:
Version: @VERSION@
Libs: -L${libdir} -lgst
Cflags:

View file

@ -84,3 +84,4 @@ make prefix=$RPM_BUILD_ROOT%{prefix} install
%{prefix}/include/* %{prefix}/include/*
%{prefix}/lib/lib*.a %{prefix}/lib/lib*.a
%{prefix}/lib/lib*.so %{prefix}/lib/lib*.so
%{prefix}/lib/pkgconfig/*

View file

@ -53,38 +53,38 @@ GstIDCT *gst_idct_new(GstIDCTMethod method)
switch (method) { switch (method) {
case GST_IDCT_FAST_INT: case GST_IDCT_FAST_INT:
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using fast_int_idct\n"); GST_INFO (GST_CAT_PLUGIN_INFO, "using fast_int_idct");
gst_idct_init_fast_int_idct(); gst_idct_init_fast_int_idct();
new->convert = gst_idct_fast_int_idct; new->convert = gst_idct_fast_int_idct;
break; break;
case GST_IDCT_INT: case GST_IDCT_INT:
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using int_idct\n"); GST_INFO (GST_CAT_PLUGIN_INFO, "using int_idct");
new->convert = gst_idct_int_idct; new->convert = gst_idct_int_idct;
break; break;
case GST_IDCT_FLOAT: case GST_IDCT_FLOAT:
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using float_idct\n"); GST_INFO (GST_CAT_PLUGIN_INFO, "using float_idct");
gst_idct_init_float_idct(); gst_idct_init_float_idct();
new->convert = gst_idct_float_idct; new->convert = gst_idct_float_idct;
break; break;
#ifdef HAVE_LIBMMX #ifdef HAVE_LIBMMX
case GST_IDCT_MMX: case GST_IDCT_MMX:
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using MMX_idct\n"); GST_INFO (GST_CAT_PLUGIN_INFO, "using MMX_idct");
new->convert = gst_idct_mmx_idct; new->convert = gst_idct_mmx_idct;
new->need_transpose = TRUE; new->need_transpose = TRUE;
break; break;
case GST_IDCT_MMX32: case GST_IDCT_MMX32:
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using MMX32_idct\n"); GST_INFO (GST_CAT_PLUGIN_INFO, "using MMX32_idct");
new->convert = gst_idct_mmx32_idct; new->convert = gst_idct_mmx32_idct;
new->need_transpose = TRUE; new->need_transpose = TRUE;
break; break;
case GST_IDCT_SSE: case GST_IDCT_SSE:
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using SSE_idct\n"); GST_INFO (GST_CAT_PLUGIN_INFO, "using SSE_idct");
new->convert = gst_idct_sse_idct; new->convert = gst_idct_sse_idct;
new->need_transpose = TRUE; new->need_transpose = TRUE;
break; break;
#endif /* HAVE_LIBMMX */ #endif /* HAVE_LIBMMX */
default: default:
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: method not supported\n"); GST_INFO (GST_CAT_PLUGIN_INFO, "method not supported");
g_free(new); g_free(new);
return NULL; return NULL;
} }

View file

@ -49,6 +49,7 @@ enum {
ARG_OUTPUT, ARG_OUTPUT,
ARG_PATTERN, ARG_PATTERN,
ARG_NUM_BUFFERS, ARG_NUM_BUFFERS,
ARG_EOS,
ARG_SILENT ARG_SILENT
}; };
@ -125,6 +126,8 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
GTK_ARG_READWRITE, ARG_PATTERN); GTK_ARG_READWRITE, ARG_PATTERN);
gtk_object_add_arg_type ("GstFakeSrc::num_buffers", GTK_TYPE_INT, gtk_object_add_arg_type ("GstFakeSrc::num_buffers", GTK_TYPE_INT,
GTK_ARG_READWRITE, ARG_NUM_BUFFERS); GTK_ARG_READWRITE, ARG_NUM_BUFFERS);
gtk_object_add_arg_type ("GstFakeSrc::eos", GTK_TYPE_BOOL,
GTK_ARG_READWRITE, ARG_EOS);
gtk_object_add_arg_type ("GstFakeSrc::silent", GTK_TYPE_BOOL, gtk_object_add_arg_type ("GstFakeSrc::silent", GTK_TYPE_BOOL,
GTK_ARG_READWRITE, ARG_SILENT); GTK_ARG_READWRITE, ARG_SILENT);
@ -222,6 +225,10 @@ gst_fakesrc_set_arg (GtkObject *object, GtkArg *arg, guint id)
case ARG_NUM_BUFFERS: case ARG_NUM_BUFFERS:
src->num_buffers = GTK_VALUE_INT (*arg); src->num_buffers = GTK_VALUE_INT (*arg);
break; break;
case ARG_EOS:
src->eos = GTK_VALUE_BOOL (*arg);
GST_INFO (0, "will EOS on next buffer");
break;
case ARG_SILENT: case ARG_SILENT:
src->silent = GTK_VALUE_BOOL (*arg); src->silent = GTK_VALUE_BOOL (*arg);
break; break;
@ -256,6 +263,8 @@ gst_fakesrc_get_arg (GtkObject *object, GtkArg *arg, guint id)
case ARG_NUM_BUFFERS: case ARG_NUM_BUFFERS:
GTK_VALUE_INT (*arg) = src->num_buffers; GTK_VALUE_INT (*arg) = src->num_buffers;
break; break;
case ARG_EOS:
GTK_VALUE_BOOL (*arg) = src->eos;
case ARG_SILENT: case ARG_SILENT:
GTK_VALUE_BOOL (*arg) = src->silent; GTK_VALUE_BOOL (*arg) = src->silent;
break; break;
@ -295,6 +304,12 @@ gst_fakesrc_get(GstPad *pad)
src->num_buffers--; src->num_buffers--;
} }
if (src->eos) {
GST_INFO (0, "fakesrc is setting eos on pad");
gst_pad_set_eos (pad);
return NULL;
}
if (!src->silent) if (!src->silent)
g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad)); g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad));
buf = gst_buffer_new(); buf = gst_buffer_new();
@ -336,7 +351,13 @@ gst_fakesrc_loop(GstElement *element)
} }
else { else {
if (src->num_buffers > 0) if (src->num_buffers > 0)
src->num_buffers--; src->num_buffers--;
}
if (src->eos) {
GST_INFO (0, "fakesrc is setting eos on pad");
gst_pad_set_eos (pad);
return;
} }
buf = gst_buffer_new(); buf = gst_buffer_new();

View file

@ -65,6 +65,7 @@ struct _GstFakeSrc {
GstElement element; GstElement element;
gboolean loop_based; gboolean loop_based;
gboolean eos;
gint numsrcpads; gint numsrcpads;
GSList *srcpads; GSList *srcpads;
GstFakeSrcOutputType output; GstFakeSrcOutputType output;

View file

@ -23,7 +23,7 @@
//#define DEBUG_ENABLED //#define DEBUG_ENABLED
//#define STATUS_ENABLED //#define STATUS_ENABLED
#ifdef STATUS_ENABLED #ifdef STATUS_ENABLED
#define STATUS(A) GST_DEBUG(0,A, gst_element_get_name(GST_ELEMENT(queue))) #define STATUS(A) GST_DEBUG(GST_CAT_DATAFLOW, A, GST_ELEMENT_NAME(queue))
#else #else
#define STATUS(A) #define STATUS(A)
#endif #endif
@ -34,6 +34,7 @@
#include "gst_private.h" #include "gst_private.h"
#include "gstqueue.h" #include "gstqueue.h"
#include "gstscheduler.h"
GstElementDetails gst_queue_details = { GstElementDetails gst_queue_details = {
"Queue", "Queue",
@ -47,15 +48,22 @@ GstElementDetails gst_queue_details = {
/* Queue signals and args */ /* Queue signals and args */
enum { enum {
/* FILL ME */ LOW_WATERMARK,
HIGH_WATERMARK,
LAST_SIGNAL LAST_SIGNAL
}; };
enum { enum {
ARG_0, ARG_0,
ARG_LEVEL_BUFFERS,
ARG_LEVEL_BYTES,
ARG_LEVEL_TIME,
ARG_SIZE_BUFFERS,
ARG_SIZE_BYTES,
ARG_SIZE_TIME,
ARG_LEAKY,
ARG_LEVEL, ARG_LEVEL,
ARG_MAX_LEVEL, ARG_MAX_LEVEL,
ARG_BLOCK,
}; };
@ -76,6 +84,23 @@ static void gst_queue_flush (GstQueue *queue);
static GstElementStateReturn gst_queue_change_state (GstElement *element); static GstElementStateReturn gst_queue_change_state (GstElement *element);
static GtkType
queue_leaky_get_type(void) {
static GtkType queue_leaky_type = 0;
static GtkEnumValue queue_leaky[] = {
{ GST_QUEUE_NO_LEAK, "0", "Not Leaky" },
{ GST_QUEUE_LEAK_UPSTREAM, "1", "Leaky on Upstream" },
{ GST_QUEUE_LEAK_DOWNSTREAM, "2", "Leaky on Downstream" },
{ 0, NULL, NULL },
};
if (!queue_leaky_type) {
queue_leaky_type = gtk_type_register_enum("GstQueueLeaky", queue_leaky);
}
return queue_leaky_type;
}
#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type())
static GstElementClass *parent_class = NULL; static GstElementClass *parent_class = NULL;
//static guint gst_queue_signals[LAST_SIGNAL] = { 0 }; //static guint gst_queue_signals[LAST_SIGNAL] = { 0 };
@ -111,12 +136,12 @@ gst_queue_class_init (GstQueueClass *klass)
parent_class = gtk_type_class (GST_TYPE_ELEMENT); parent_class = gtk_type_class (GST_TYPE_ELEMENT);
gtk_object_add_arg_type ("GstQueue::leaky", GST_TYPE_QUEUE_LEAKY,
GTK_ARG_READWRITE, ARG_LEAKY);
gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT, gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT,
GTK_ARG_READABLE, ARG_LEVEL); GTK_ARG_READABLE, ARG_LEVEL);
gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT, gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT,
GTK_ARG_READWRITE, ARG_MAX_LEVEL); GTK_ARG_READWRITE, ARG_MAX_LEVEL);
gtk_object_add_arg_type ("GstQueue::block", GTK_TYPE_BOOL,
GTK_ARG_READWRITE, ARG_BLOCK);
gtkobject_class->set_arg = gst_queue_set_arg; gtkobject_class->set_arg = gst_queue_set_arg;
gtkobject_class->get_arg = gst_queue_get_arg; gtkobject_class->get_arg = gst_queue_get_arg;
@ -144,14 +169,15 @@ gst_queue_init (GstQueue *queue)
queue->queue = NULL; queue->queue = NULL;
queue->level_buffers = 0; queue->level_buffers = 0;
queue->max_buffers = 100;
queue->block = TRUE;
queue->level_bytes = 0; queue->level_bytes = 0;
queue->size_buffers = 0; queue->level_time = 0LL;
queue->size_bytes = 0; queue->size_buffers = 100; // 100 buffers
queue->size_bytes = 100 * 1024; // 100KB
queue->size_time = 1000000000LL; // 1sec
queue->emptycond = g_cond_new (); queue->emptycond = g_cond_new ();
queue->fullcond = g_cond_new (); queue->fullcond = g_cond_new ();
GST_DEBUG(GST_CAT_THREAD, "initialized queue's emptycond and fullcond\n");
} }
static GstBufferPool* static GstBufferPool*
@ -206,10 +232,10 @@ gst_queue_handle_eos (GstPad *pad)
queue = GST_QUEUE (GST_OBJECT_PARENT (pad)); queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
GST_DEBUG (0,"queue: %s received eos\n", GST_ELEMENT_NAME (queue)); GST_DEBUG (GST_CAT_DATAFLOW,"%s received eos\n", GST_ELEMENT_NAME (queue));
GST_LOCK (queue); GST_LOCK (queue);
GST_DEBUG (0,"queue: %s has %d buffers left\n", GST_ELEMENT_NAME (queue), GST_DEBUG (GST_CAT_DATAFLOW,"%s has %d buffers left\n", GST_ELEMENT_NAME (queue),
queue->level_buffers); queue->level_buffers);
GST_FLAG_SET (pad, GST_PAD_EOS); GST_FLAG_SET (pad, GST_PAD_EOS);
@ -224,7 +250,7 @@ gst_queue_handle_eos (GstPad *pad)
static void static void
gst_queue_cleanup_buffers (gpointer data, const gpointer user_data) gst_queue_cleanup_buffers (gpointer data, const gpointer user_data)
{ {
GST_DEBUG (0,"queue: %s cleaning buffer %p\n", (gchar *)user_data, data); GST_DEBUG (GST_CAT_DATAFLOW,"%s cleaning buffer %p\n", (gchar *)user_data, data);
gst_buffer_unref (GST_BUFFER (data)); gst_buffer_unref (GST_BUFFER (data));
} }
@ -257,45 +283,79 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf)
/* we have to lock the queue since we span threads */ /* we have to lock the queue since we span threads */
GST_DEBUG (0,"queue: try have queue lock\n"); // GST_DEBUG (GST_CAT_DATAFLOW,"trying to get lock on queue \"%s\"\n",name);
GST_LOCK (queue); GST_LOCK (queue);
GST_DEBUG (0,"queue: %s adding buffer %p %ld\n", name, buf, pthread_self ());
GST_DEBUG (0,"queue: have queue lock\n");
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) { if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) {
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "buffer has FLUSH bit set, flushing queue\n");
gst_queue_flush (queue); gst_queue_flush (queue);
} }
GST_DEBUG (0,"queue: %s: chain %d %p\n", name, queue->level_buffers, buf); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "adding buffer %p of size %d\n",buf,GST_BUFFER_SIZE(buf));
while (queue->level_buffers >= queue->max_buffers) { if (queue->level_buffers >= queue->size_buffers) {
GST_DEBUG (0,"queue: %s waiting %d\n", name, queue->level_buffers); // if this is a leaky queue...
STATUS("%s: O\n"); if (queue->leaky) {
//g_cond_timed_wait (queue->fullcond, queue->fulllock, queue->timeval); // if we leak on the upstream side, drop the current buffer
//FIXME need to signal other thread in case signals got lost? if (queue->leaky == GST_QUEUE_LEAK_UPSTREAM) {
g_cond_signal (queue->emptycond); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on upstream end\n");
g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock); gst_buffer_unref(buf);
STATUS("%s: O+\n"); // now we have to clean up and exit right away
GST_DEBUG (0,"queue: %s waiting done %d\n", name, queue->level_buffers); GST_UNLOCK (queue);
return;
}
// otherwise we have to push a buffer off the other end
else {
GSList *front;
GstBuffer *leakbuf;
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end\n");
front = queue->queue;
leakbuf = (GstBuffer *)(front->data);
queue->level_buffers--;
queue->level_bytes -= GST_BUFFER_SIZE(leakbuf);
gst_buffer_unref(leakbuf);
queue->queue = g_slist_remove_link (queue->queue, front);
g_slist_free (front);
}
}
while (queue->level_buffers >= queue->size_buffers) {
// if there's a pending state change for this queue or its manager, switch
// back to iterator so bottom half of state change executes
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
// GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->sinkpad))))) !=
GST_STATE_NONE_PENDING)
{
GST_DEBUG(GST_CAT_DATAFLOW,"interrupted!!\n");
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)\n");
if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING\n");
GST_UNLOCK(queue);
cothread_switch(cothread_current_main());
}
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "waiting for space, level is %d\n", queue->level_buffers);
g_cond_signal (queue->emptycond);
g_cond_wait (queue->fullcond, GST_OBJECT(queue)->lock);
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "done waiting, level is now %d\n", queue->level_buffers);
}
} }
/* put the buffer on the tail of the list */ /* put the buffer on the tail of the list */
queue->queue = g_slist_append (queue->queue, buf); queue->queue = g_slist_append (queue->queue, buf);
// STATUS("%s: +\n"); queue->level_buffers++;
GST_DEBUG (0,"(%s:%s)+ ",GST_DEBUG_PAD_NAME(pad)); queue->level_bytes += GST_BUFFER_SIZE(buf);
// GST_DEBUG (GST_CAT_DATAFLOW, "(%s:%s)+\n",GST_DEBUG_PAD_NAME(pad));
/* if we were empty, but aren't any more, signal a condition */ /* if we were empty, but aren't any more, signal a condition */
tosignal = (queue->level_buffers >= 0); if (queue->level_buffers == 1)
queue->level_buffers++; {
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling emptycond\n", name);
/* we can unlock now */
GST_DEBUG (0,"queue: %s chain %d end signal(%d,%p)\n", name, queue->level_buffers, tosignal, queue->emptycond);
if (tosignal) {
// STATUS("%s: >\n");
g_cond_signal (queue->emptycond); g_cond_signal (queue->emptycond);
// STATUS("%s: >>\n");
} }
GST_UNLOCK (queue); GST_UNLOCK (queue);
} }
@ -307,6 +367,8 @@ gst_queue_get (GstPad *pad)
GSList *front; GSList *front;
const guchar *name; const guchar *name;
g_assert(pad != NULL);
g_assert(GST_IS_PAD(pad));
g_return_val_if_fail (pad != NULL, NULL); g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_IS_PAD (pad), NULL); g_return_val_if_fail (GST_IS_PAD (pad), NULL);
@ -314,63 +376,74 @@ gst_queue_get (GstPad *pad)
name = GST_ELEMENT_NAME (queue); name = GST_ELEMENT_NAME (queue);
/* have to lock for thread-safety */ /* have to lock for thread-safety */
GST_DEBUG (0,"queue: %s try have queue lock\n", name); GST_DEBUG (GST_CAT_DATAFLOW,"%s try have queue lock\n", name);
GST_LOCK (queue); GST_LOCK (queue);
GST_DEBUG (0,"queue: %s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond); GST_DEBUG (GST_CAT_DATAFLOW,"%s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
GST_DEBUG (0,"queue: %s have queue lock\n", name); GST_DEBUG (GST_CAT_DATAFLOW,"%s have queue lock\n", name);
// we bail if there's nothing there
if (!queue->level_buffers && !queue->block) {
GST_UNLOCK(queue);
return NULL;
}
while (!queue->level_buffers) { while (!queue->level_buffers) {
STATUS("queue: %s U released lock\n");
//g_cond_timed_wait (queue->emptycond, queue->emptylock, queue->timeval);
if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) { if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) {
GST_DEBUG (GST_CAT_DATAFLOW, "%s U released lock\n", name);
GST_UNLOCK(queue);
gst_pad_set_eos (queue->srcpad); gst_pad_set_eos (queue->srcpad);
// this return NULL shouldn't hurt anything...
return NULL; return NULL;
} }
//FIXME need to signal other thread in case signals got lost?
// if there's a pending state change for this queue or its manager, switch
// back to iterator so bottom half of state change executes
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
// GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->srcpad))))) !=
GST_STATE_NONE_PENDING)
{
GST_DEBUG(GST_CAT_DATAFLOW,"interrupted!!\n");
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)\n");
if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING\n");
GST_UNLOCK(queue);
cothread_switch(cothread_current_main());
}
g_cond_signal (queue->fullcond); g_cond_signal (queue->fullcond);
g_cond_wait (queue->emptycond, GST_OBJECT(queue)->lock); g_cond_wait (queue->emptycond, GST_OBJECT(queue)->lock);
// STATUS("queue: %s U- getting lock\n");
} }
front = queue->queue; front = queue->queue;
buf = (GstBuffer *)(front->data); buf = (GstBuffer *)(front->data);
GST_DEBUG (0,"retrieved buffer %p from queue\n",buf); GST_DEBUG (GST_CAT_DATAFLOW,"retrieved buffer %p from queue\n",buf);
queue->queue = g_slist_remove_link (queue->queue, front); queue->queue = g_slist_remove_link (queue->queue, front);
g_slist_free (front); g_slist_free (front);
queue->level_buffers--; // if (queue->level_buffers < queue->size_buffers)
// STATUS("%s: -\n"); if (queue->level_buffers == queue->size_buffers)
GST_DEBUG (0,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad)); {
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling fullcond\n", name);
if (queue->level_buffers < queue->max_buffers) {
// STATUS("%s: < \n");
g_cond_signal (queue->fullcond); g_cond_signal (queue->fullcond);
// STATUS("%s: << \n");
} }
queue->level_buffers--;
queue->level_bytes -= GST_BUFFER_SIZE(buf);
GST_DEBUG (GST_CAT_DATAFLOW,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
GST_UNLOCK(queue); GST_UNLOCK(queue);
// GST_DEBUG (0,"queue: %s pushing %d %p \n", name, queue->level_buffers, buf);
// gst_pad_push (queue->srcpad, buf);
// GST_DEBUG (0,"queue: %s pushing %d done \n", name, queue->level_buffers);
return buf; return buf;
/* unlock now */
} }
static GstElementStateReturn static GstElementStateReturn
gst_queue_change_state (GstElement *element) gst_queue_change_state (GstElement *element)
{ {
GstQueue *queue; GstQueue *queue;
GstElementStateReturn ret;
g_return_val_if_fail (GST_IS_QUEUE (element), GST_STATE_FAILURE); g_return_val_if_fail (GST_IS_QUEUE (element), GST_STATE_FAILURE);
queue = GST_QUEUE (element); queue = GST_QUEUE (element);
GST_DEBUG (0,"gstqueue: state pending %d\n", GST_STATE_PENDING (element));
// lock the queue so another thread (not in sync with this thread's state)
// can't call this queue's _get (or whatever)
GST_LOCK (queue);
/* if going down into NULL state, clear out buffers*/ /* if going down into NULL state, clear out buffers*/
if (GST_STATE_PENDING (element) == GST_STATE_READY) { if (GST_STATE_PENDING (element) == GST_STATE_READY) {
@ -380,9 +453,41 @@ gst_queue_change_state (GstElement *element)
/* if we haven't failed already, give the parent class a chance to ;-) */ /* if we haven't failed already, give the parent class a chance to ;-) */
if (GST_ELEMENT_CLASS (parent_class)->change_state) if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element); {
gboolean valid_handler = FALSE;
guint state_change_id = gtk_signal_lookup("state_change", GTK_OBJECT_TYPE(element));
return GST_STATE_SUCCESS; // determine whether we need to block the parent (element) class'
// STATE_CHANGE signal so we can UNLOCK before returning. we block
// it if we could find the state_change signal AND there's a signal
// handler attached to it.
//
// note: this assumes that change_state() *only* emits state_change signal.
// if element change_state() emits other signals, they need to be blocked
// as well.
if (state_change_id &&
gtk_signal_handler_pending(GTK_OBJECT(element), state_change_id, FALSE))
valid_handler = TRUE;
if (valid_handler)
gtk_signal_handler_block(GTK_OBJECT(element), state_change_id);
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
if (valid_handler)
gtk_signal_handler_unblock(GTK_OBJECT(element), state_change_id);
// UNLOCK, *then* emit signal (if there's one there)
GST_UNLOCK(queue);
if (valid_handler)
gtk_signal_emit(GTK_OBJECT (element), state_change_id, GST_STATE(element));
}
else
{
ret = GST_STATE_SUCCESS;
GST_UNLOCK(queue);
}
return ret;
} }
@ -397,11 +502,11 @@ gst_queue_set_arg (GtkObject *object, GtkArg *arg, guint id)
queue = GST_QUEUE (object); queue = GST_QUEUE (object);
switch(id) { switch(id) {
case ARG_MAX_LEVEL: case ARG_LEAKY:
queue->max_buffers = GTK_VALUE_INT (*arg); queue->leaky = GTK_VALUE_INT (*arg);
break; break;
case ARG_BLOCK: case ARG_MAX_LEVEL:
queue->block = GTK_VALUE_BOOL (*arg); queue->size_buffers = GTK_VALUE_INT (*arg);
break; break;
default: default:
break; break;
@ -419,14 +524,14 @@ gst_queue_get_arg (GtkObject *object, GtkArg *arg, guint id)
queue = GST_QUEUE (object); queue = GST_QUEUE (object);
switch (id) { switch (id) {
case ARG_LEAKY:
GTK_VALUE_INT (*arg) = queue->leaky;
break;
case ARG_LEVEL: case ARG_LEVEL:
GTK_VALUE_INT (*arg) = queue->level_buffers; GTK_VALUE_INT (*arg) = queue->level_buffers;
break; break;
case ARG_MAX_LEVEL: case ARG_MAX_LEVEL:
GTK_VALUE_INT (*arg) = queue->max_buffers; GTK_VALUE_INT (*arg) = queue->size_buffers;
break;
case ARG_BLOCK:
GTK_VALUE_BOOL (*arg) = queue->block;
break; break;
default: default:
arg->type = GTK_TYPE_INVALID; arg->type = GTK_TYPE_INVALID;

View file

@ -47,6 +47,12 @@ GstElementDetails gst_queue_details;
#define GST_IS_QUEUE_CLASS(obj) \ #define GST_IS_QUEUE_CLASS(obj) \
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE)) (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
enum {
GST_QUEUE_NO_LEAK = 0,
GST_QUEUE_LEAK_UPSTREAM = 1,
GST_QUEUE_LEAK_DOWNSTREAM = 2
};
typedef struct _GstQueue GstQueue; typedef struct _GstQueue GstQueue;
typedef struct _GstQueueClass GstQueueClass; typedef struct _GstQueueClass GstQueueClass;
@ -60,12 +66,16 @@ struct _GstQueue {
GSList *queue; GSList *queue;
gint level_buffers; /* number of buffers queued here */ gint level_buffers; /* number of buffers queued here */
gint max_buffers; /* maximum number of buffers queued here */
gboolean block; /* if set to FALSE, _get returns NULL if queue empty */
gint level_bytes; /* number of bytes queued here */ gint level_bytes; /* number of bytes queued here */
guint64 level_time; /* amount of time queued here */
gint size_buffers; /* size of queue in buffers */ gint size_buffers; /* size of queue in buffers */
gint size_bytes; /* size of queue in bytes */ gint size_bytes; /* size of queue in bytes */
guint64 size_time; /* size of queue in time */
gint leaky; /* whether the queue is leaky, and if so at which end */
// GMutex *lock; (optimization?)
GCond *emptycond; GCond *emptycond;
GCond *fullcond; GCond *fullcond;
@ -74,6 +84,10 @@ struct _GstQueue {
struct _GstQueueClass { struct _GstQueueClass {
GstElementClass parent_class; GstElementClass parent_class;
/* signal callbacks */
void (*low_watermark) (GstQueue *queue, gint level);
void (*high_watermark) (GstQueue *queue, gint level);
}; };
GtkType gst_queue_get_type (void); GtkType gst_queue_get_type (void);

View file

@ -407,4 +407,4 @@ gst_sinesrc_factory_init (GstElementFactory *factory)
gst_elementfactory_add_padtemplate (factory, src_temp); gst_elementfactory_add_padtemplate (factory, src_temp);
return TRUE; return TRUE;
} }

1
test/.gitignore vendored
View file

@ -29,6 +29,7 @@ mp3parse
mpeg2parse mpeg2parse
mpeg2parse2 mpeg2parse2
mpeg2parse3 mpeg2parse3
mpeg2parse4
mp3play mp3play
ac3parse ac3parse
ac3play ac3play

View file

@ -22,18 +22,6 @@ ac3play_SOURCES = ac3play.c mem.c
noinst_HEADERS = mem.h noinst_HEADERS = mem.h
if HAVE_LIBXV
xvlibs=-lXv
else
xvlibs=
endif
LDADD = ${xvlibs} -lXxf86vm $(GNOME_LIBS) $(GST_LIBS)
#LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la \
# $(top_builddir)/plugins/videosink/libvideosink.la -L/usr/X11/lib -lXxf86dga
#LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la
LIBS += $(GNOME_LIBS) $(GST_LIBS) LIBS += $(GNOME_LIBS) $(GST_LIBS)
CFLAGS += $(GNOME_CFLAGS) $(GST_CFLAGS) CFLAGS += $(GNOME_CFLAGS) $(GST_CFLAGS)

View file

@ -141,7 +141,7 @@ int main(int argc,char *argv[]) {
g_return_val_if_fail(src != NULL, -1); g_return_val_if_fail(src != NULL, -1);
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL); gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
g_print("should be using file '%s'\n",argv[1]); g_print("should be using file '%s'\n",argv[1]);
parse = gst_elementfactory_make("parseavi","parse"); parse = gst_elementfactory_make("avidecoder","parse");
g_return_val_if_fail(parse != NULL, -1); g_return_val_if_fail(parse != NULL, -1);
mux = gst_elementfactory_make("system_encode","mux"); mux = gst_elementfactory_make("system_encode","mux");

View file

@ -32,8 +32,6 @@ int main(int argc,char *argv[]) {
gst_pad_connect(gst_element_get_pad(identity,"src"), gst_pad_connect(gst_element_get_pad(identity,"src"),
gst_element_get_pad(sink,"sink")); gst_element_get_pad(sink,"sink"));
g_print("--- creating a plan\n");
gst_bin_create_plan(GST_BIN(bin));
g_print("--- starting up\n"); g_print("--- starting up\n");
gst_bin_iterate(GST_BIN(bin)); gst_bin_iterate(GST_BIN(bin));

View file

@ -29,7 +29,7 @@ main (int argc,char *argv[])
gnome_init("Videotest","0.0.1",argc,argv); gnome_init("Videotest","0.0.1",argc,argv);
bin = gst_bin_new("bin"); bin = gst_pipeline_new("pipeline");
if (argc == 1) { if (argc == 1) {
src = gst_elementfactory_make ("dv1394src", "src"); src = gst_elementfactory_make ("dv1394src", "src");

View file

@ -10,7 +10,7 @@ int main(int argc,char *argv[]) {
// _gst_plugin_spew = TRUE; // _gst_plugin_spew = TRUE;
gst_init(&argc,&argv); gst_init(&argc,&argv);
bin = gst_bin_new("bin"); bin = gst_pipeline_new("pipeline");
g_return_if_fail(bin != NULL); g_return_if_fail(bin != NULL);
g_print("--- creating src and sink elements\n"); g_print("--- creating src and sink elements\n");
@ -35,8 +35,6 @@ int main(int argc,char *argv[]) {
g_print("--- setting up\n"); g_print("--- setting up\n");
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_READY); gst_element_set_state(GST_ELEMENT(bin),GST_STATE_READY);
g_print("--- creating plan\n");
gst_bin_create_plan(bin);
g_print("--- iterating\n"); g_print("--- iterating\n");
gst_bin_iterate(bin); gst_bin_iterate(bin);
} }

View file

@ -86,6 +86,7 @@ int main(int argc,char *argv[]) {
gtk_socket = gtk_socket_new (); gtk_socket = gtk_socket_new ();
gtk_widget_show (gtk_socket); gtk_widget_show (gtk_socket);
gtk_widget_set_usize(gtk_socket,320,240);
gnome_app_set_contents(GNOME_APP(appwindow), gnome_app_set_contents(GNOME_APP(appwindow),
GTK_WIDGET(gtk_socket)); GTK_WIDGET(gtk_socket));

View file

@ -1,8 +1,10 @@
#include <gnome.h> #include <gnome.h>
#include <gst/gst.h> #include <gst/gst.h>
GstElement *parse2, *v_queue, *a_queue; GstPipeline *pipeline;
GstElement *v_queue, *a_queue, *v_thread, *a_thread;
GtkWidget *appwindow; GtkWidget *appwindow;
GtkWidget *gtk_socket;
void eof(GstElement *src) { void eof(GstElement *src) {
g_print("have eos, quitting\n"); g_print("have eos, quitting\n");
@ -17,38 +19,37 @@ gboolean idle_func(gpointer data) {
void mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) { void mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) {
g_print("***** a new pad %s was created\n", gst_pad_get_name(pad)); g_print("***** a new pad %s was created\n", gst_pad_get_name(pad));
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PAUSED);
if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) { if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) {
gst_pad_connect(pad, gst_element_get_pad(v_queue,"sink")); gst_pad_connect(pad, gst_element_get_pad(v_queue,"sink"));
gst_bin_add(GST_BIN(pipeline),v_thread);
gst_element_set_state(v_thread,GST_STATE_PLAYING);
} else if (strcmp(gst_pad_get_name(pad), "private_stream_1.0") == 0) { } else if (strcmp(gst_pad_get_name(pad), "private_stream_1.0") == 0) {
gst_pad_connect(pad, gst_element_get_pad(a_queue,"sink")); gst_pad_connect(pad, gst_element_get_pad(a_queue,"sink"));
gst_bin_add(GST_BIN(pipeline),a_thread);
gst_element_set_state(a_thread,GST_STATE_PLAYING);
} }
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING); }
void mpeg2parse_have_size(GstElement *videosink,gint width,gint height) {
gtk_widget_set_usize(gtk_socket,width,height);
gtk_widget_show_all(appwindow);
} }
int main(int argc,char *argv[]) { int main(int argc,char *argv[]) {
GstPipeline *pipeline;
GstElement *src, *parse; GstElement *src, *parse;
GstElement *v_thread, *v_decode, *show, *color; GstElement *v_decode, *show, *color;
GstElement *a_thread, *a_decode, *osssink; GstElement *a_decode, *osssink;
GtkWidget *gtk_socket;
g_print("have %d args\n",argc); g_print("have %d args\n",argc);
gst_init(&argc,&argv); gst_init(&argc,&argv);
gnome_init("MPEG2 Video player","0.0.1",argc,argv); gnome_init("MPEG2 Video player","0.0.1",argc,argv);
//gst_plugin_load("mpeg1parse");
// ***** construct the main pipeline *****
pipeline = GST_PIPELINE(gst_pipeline_new("pipeline")); pipeline = GST_PIPELINE(gst_pipeline_new("pipeline"));
g_return_val_if_fail(pipeline != NULL, -1); g_return_val_if_fail(pipeline != NULL, -1);
v_thread = GST_ELEMENT(gst_thread_new("v_thread"));
g_return_val_if_fail(v_thread != NULL, -1);
a_thread = GST_ELEMENT(gst_thread_new("a_thread"));
g_return_val_if_fail(a_thread != NULL, -1);
if (strstr(argv[1],"video_ts")) { if (strstr(argv[1],"video_ts")) {
src = gst_elementfactory_make("dvdsrc","src"); src = gst_elementfactory_make("dvdsrc","src");
g_print("using DVD source\n"); g_print("using DVD source\n");
@ -68,20 +69,19 @@ int main(int argc,char *argv[]) {
//parse = gst_elementfactory_make("mpeg1parse","parse"); //parse = gst_elementfactory_make("mpeg1parse","parse");
g_return_val_if_fail(parse != NULL, -1); g_return_val_if_fail(parse != NULL, -1);
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
gst_element_connect(src,"src",parse,"sink");
// ***** pre-construct the video thread *****
v_thread = GST_ELEMENT(gst_thread_new("v_thread"));
g_return_val_if_fail(v_thread != NULL, -1);
v_queue = gst_elementfactory_make("queue","v_queue"); v_queue = gst_elementfactory_make("queue","v_queue");
g_return_val_if_fail(v_queue != NULL, -1); g_return_val_if_fail(v_queue != NULL, -1);
a_queue = gst_elementfactory_make("queue","a_queue");
g_return_val_if_fail(a_queue != NULL, -1);
/****
* you can substitute mpeg2play with you own player here
* optionally you can remove the parse2 element. make
* sure to remove the pad connections too and don't add the
* mp2videoparse element to the bin.
**/
//parse2 = gst_elementfactory_make("mp2videoparse","parse");
//g_return_val_if_fail(parse2 != NULL, -1);
v_decode = gst_elementfactory_make("mpeg2dec","decode_video"); v_decode = gst_elementfactory_make("mpeg2dec","decode_video");
g_return_val_if_fail(v_decode != NULL, -1); g_return_val_if_fail(v_decode != NULL, -1);
@ -89,16 +89,40 @@ int main(int argc,char *argv[]) {
g_return_val_if_fail(color != NULL, -1); g_return_val_if_fail(color != NULL, -1);
show = gst_elementfactory_make("xvideosink","show"); show = gst_elementfactory_make("xvideosink","show");
//show = gst_elementfactory_make("aasink","show");
//gtk_object_set(GTK_OBJECT(show),"xv_enabled",FALSE,NULL);
g_return_val_if_fail(show != NULL, -1); g_return_val_if_fail(show != NULL, -1);
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_queue));
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_decode));
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(color));
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(show));
gst_element_connect(v_queue,"src",v_decode,"sink");
gst_element_connect(v_decode,"src",color,"sink");
gst_element_connect(color,"src",show,"sink");
// ***** pre-construct the audio thread *****
a_thread = GST_ELEMENT(gst_thread_new("a_thread"));
g_return_val_if_fail(a_thread != NULL, -1);
a_queue = gst_elementfactory_make("queue","a_queue");
g_return_val_if_fail(a_queue != NULL, -1);
a_decode = gst_elementfactory_make("ac3dec","decode_audio"); a_decode = gst_elementfactory_make("ac3dec","decode_audio");
g_return_val_if_fail(a_decode != NULL, -1); g_return_val_if_fail(a_decode != NULL, -1);
osssink = gst_elementfactory_make("osssink","osssink"); osssink = gst_elementfactory_make("osssink","osssink");
g_return_val_if_fail(osssink != NULL, -1); g_return_val_if_fail(osssink != NULL, -1);
gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_queue));
gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_decode));
gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(osssink));
gst_element_connect(a_queue,"src",a_decode,"sink");
gst_element_connect(a_decode,"src",osssink,"sink");
// ***** construct the GUI *****
appwindow = gnome_app_new("MPEG player","MPEG player"); appwindow = gnome_app_new("MPEG player","MPEG player");
gtk_socket = gtk_socket_new (); gtk_socket = gtk_socket_new ();
@ -111,45 +135,9 @@ int main(int argc,char *argv[]) {
gtk_socket_steal (GTK_SOCKET (gtk_socket), gtk_socket_steal (GTK_SOCKET (gtk_socket),
gst_util_get_int_arg (GTK_OBJECT(show), "xid")); gst_util_get_int_arg (GTK_OBJECT(show), "xid"));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(v_queue));
//gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(parse2));
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_decode));
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(color));
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(show));
gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_decode));
gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(osssink));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(v_thread));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(a_thread));
gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad, pipeline); gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad, pipeline);
gtk_signal_connect(GTK_OBJECT(src),"eos",GTK_SIGNAL_FUNC(eof),NULL); gtk_signal_connect(GTK_OBJECT(src),"eos",GTK_SIGNAL_FUNC(eof),NULL);
gtk_signal_connect(GTK_OBJECT(show),"have_size",mpeg2parse_have_size, pipeline);
gst_pad_connect(gst_element_get_pad(src,"src"),
gst_element_get_pad(parse,"sink"));
// video
gst_pad_connect(gst_element_get_pad(v_queue,"src"),
// gst_element_get_pad(parse2,"sink"));
//gst_pad_connect(gst_element_get_pad(parse2,"src"),
gst_element_get_pad(v_decode,"sink"));
gst_pad_connect(gst_element_get_pad(v_decode,"src"),
gst_element_get_pad(color,"sink"));
gst_pad_connect(gst_element_get_pad(color,"src"),
gst_element_get_pad(show,"sink"));
// audio
gst_pad_connect(gst_element_get_pad(a_queue,"src"),
gst_element_get_pad(a_decode,"sink"));
gst_pad_connect(gst_element_get_pad(a_decode,"src"),
gst_element_get_pad(osssink,"sink"));
gtk_widget_show_all(appwindow);
g_print("setting to PLAYING state\n"); g_print("setting to PLAYING state\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING); gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);

224
test/mpeg2parse4.c Normal file
View file

@ -0,0 +1,224 @@
#include <gnome.h>
#include <gst/gst.h>
GstElement *pipeline, *src, *parse;
GstElement *v_decode_thread, *v_decode_queue, *v_decode, *v_color;
GstElement *v_show_thread, *v_show_queue, *v_show;
GstElement *a_decode_thread, *a_decode_queue, *a_decode;
GstElement *a_sink_thread, *a_sink_queue, *a_sink;
GtkWidget *appwindow;
GtkWidget *gtk_socket;
void eof(GstElement *src) {
fprintf(stderr,"have eos, quitting\n");
exit(0);
}
gboolean idle_func(gpointer data) {
gst_bin_iterate(GST_BIN(data));
return TRUE;
}
int mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) {
fprintf(stderr,"***** a new pad %s was created\n", gst_pad_get_name(pad));
if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) {
// build the decoder thread
v_decode_thread = GST_ELEMENT(gst_thread_new("v_decode_thread"));
g_return_val_if_fail(v_decode_thread != NULL, -1);
v_decode_queue = gst_elementfactory_make("queue","v_decode_queue");
g_return_val_if_fail(v_decode_queue != NULL, -1);
v_decode = gst_elementfactory_make("mpeg2dec","v_decode");
g_return_val_if_fail(v_decode != NULL, -1);
v_color = gst_elementfactory_make("colorspace","v_color");
g_return_val_if_fail(v_color != NULL, -1);
gst_bin_add(GST_BIN(v_decode_thread),GST_ELEMENT(v_decode_queue));
gst_bin_add(GST_BIN(v_decode_thread),GST_ELEMENT(v_decode));
gst_bin_add(GST_BIN(v_decode_thread),GST_ELEMENT(v_color));
gst_element_connect(v_decode_queue,"src",v_decode,"sink");
gst_element_connect(v_decode,"src",v_color,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
// build the show thread
v_show_thread = GST_ELEMENT(gst_thread_new("v_show_thread"));
g_return_val_if_fail(v_show_thread != NULL, -1);
v_show_queue = gst_elementfactory_make("queue","v_show_queue");
g_return_val_if_fail(v_show_queue != NULL, -1);
// v_show has ben created earlier
gst_bin_add(GST_BIN(v_show_thread),GST_ELEMENT(v_show_queue));
gst_bin_add(GST_BIN(v_show_thread),GST_ELEMENT(v_show));
gst_element_connect(v_show_queue,"src",v_show,"sink");
// now assemble the decoder threads
gst_bin_add(GST_BIN(v_decode_thread),v_show_thread);
gst_element_connect(v_color,"src",v_show_queue,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
gst_schedule_show(GST_ELEMENT_SCHED(v_show_thread));
// connect the whole thing to the main pipeline
gst_pad_connect(pad, gst_element_get_pad(v_decode_queue,"sink"));
gst_bin_add(GST_BIN(pipeline),v_decode_thread);
gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
gst_schedule_show(GST_ELEMENT_SCHED(v_show_thread));
// start it playing
gst_element_set_state(v_decode_thread,GST_STATE_PLAYING);
} else if (strcmp(gst_pad_get_name(pad), "private_stream_1.0") == 0) {
// build the decoder thread
a_decode_thread = GST_ELEMENT(gst_thread_new("a_decode_thread"));
g_return_val_if_fail(a_decode_thread != NULL, -1);
a_decode_queue = gst_elementfactory_make("queue","a_decode_queue");
g_return_val_if_fail(a_decode_queue != NULL, -1);
a_decode = gst_elementfactory_make("ac3dec","a_decode");
g_return_val_if_fail(a_decode != NULL, -1);
gst_bin_add(GST_BIN(a_decode_thread),GST_ELEMENT(a_decode_queue));
gst_bin_add(GST_BIN(a_decode_thread),GST_ELEMENT(a_decode));
gst_element_connect(a_decode_queue,"src",a_decode,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
// build the sink thread
a_sink_thread = GST_ELEMENT(gst_thread_new("a_sink_thread"));
g_return_val_if_fail(a_sink_thread != NULL, -1);
a_sink_queue = gst_elementfactory_make("queue","a_sink_queue");
g_return_val_if_fail(a_sink_queue != NULL, -1);
a_sink = gst_elementfactory_make("esdsink","a_sink");
g_return_val_if_fail(a_sink != NULL, -1);
gst_bin_add(GST_BIN(a_sink_thread),GST_ELEMENT(a_sink_queue));
gst_bin_add(GST_BIN(a_sink_thread),GST_ELEMENT(a_sink));
gst_element_connect(a_sink_queue,"src",a_sink,"sink");
// now assemble the decoder threads
gst_bin_add(GST_BIN(a_decode_thread),a_sink_thread);
gst_element_connect(a_decode,"src",a_sink_queue,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
gst_schedule_show(GST_ELEMENT_SCHED(a_sink_thread));
// connect the whole thing to the main pipeline
gst_pad_connect(pad, gst_element_get_pad(a_decode_queue,"sink"));
gst_bin_add(GST_BIN(pipeline),a_decode_thread);
gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
gst_schedule_show(GST_ELEMENT_SCHED(a_sink_thread));
// start it playing
gst_element_set_state(a_decode_thread,GST_STATE_PLAYING);
}
if (v_decode_thread && a_decode_thread) {
xmlSaveFile("mpeg2parse4.gst", gst_xml_write(GST_ELEMENT(pipeline)));
fprintf(stderr,"DUMP OF ALL SCHEDULES!!!:\n");
gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
gst_schedule_show(GST_ELEMENT_SCHED(v_decode_thread));
gst_schedule_show(GST_ELEMENT_SCHED(v_show_thread));
gst_schedule_show(GST_ELEMENT_SCHED(a_decode_thread));
gst_schedule_show(GST_ELEMENT_SCHED(a_sink_thread));
}
return 0;
}
void mpeg2parse_have_size(GstElement *videosink,gint width,gint height) {
gtk_widget_set_usize(gtk_socket,width,height);
gtk_widget_show_all(appwindow);
}
int main(int argc,char *argv[]) {
g_print("have %d args\n",argc);
gst_init(&argc,&argv);
gnome_init("MPEG2 Video player","0.0.1",argc,argv);
// ***** construct the main pipeline *****
pipeline = gst_pipeline_new("pipeline");
g_return_val_if_fail(pipeline != NULL, -1);
if (strstr(argv[1],"video_ts")) {
src = gst_elementfactory_make("dvdsrc","src");
g_print("using DVD source\n");
} else {
src = gst_elementfactory_make("disksrc","src");
}
g_return_val_if_fail(src != NULL, -1);
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
if (argc >= 3) {
gtk_object_set(GTK_OBJECT(src),"bytesperread",atoi(argv[2]),NULL);
g_print("block size is %d\n",atoi(argv[2]));
}
g_print("should be using file '%s'\n",argv[1]);
parse = gst_elementfactory_make("mpeg2parse","parse");
//parse = gst_elementfactory_make("mpeg1parse","parse");
g_return_val_if_fail(parse != NULL, -1);
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
gst_element_connect(src,"src",parse,"sink");
// create v_show early so we can get and connect stuff
v_show = gst_elementfactory_make("xvideosink","v_show");
g_return_val_if_fail(v_show != NULL, -1);
// ***** construct the GUI *****
appwindow = gnome_app_new("MPEG player","MPEG player");
gtk_socket = gtk_socket_new ();
gtk_widget_show (gtk_socket);
gnome_app_set_contents(GNOME_APP(appwindow),
GTK_WIDGET(gtk_socket));
gtk_widget_realize (gtk_socket);
gtk_socket_steal (GTK_SOCKET (gtk_socket),
gst_util_get_int_arg (GTK_OBJECT(v_show), "xid"));
gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad, pipeline);
gtk_signal_connect(GTK_OBJECT(src),"eos",GTK_SIGNAL_FUNC(eof),NULL);
gtk_signal_connect(GTK_OBJECT(v_show),"have_size",mpeg2parse_have_size, pipeline);
fprintf(stderr,"setting to PLAYING state\n");
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
gtk_idle_add(idle_func,pipeline);
gdk_threads_enter();
gtk_main();
gdk_threads_leave();
return 0;
}

View file

@ -54,7 +54,6 @@ gst_play_typefind (GstBin *bin, GstElement *element)
gst_pad_disconnect (gst_element_get_pad (element, "src"), gst_pad_disconnect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink")); gst_element_get_pad (typefind, "sink"));
gst_bin_remove (bin, typefind); gst_bin_remove (bin, typefind);
gst_object_unref (GST_OBJECT (typefind));
return caps; return caps;
} }
@ -174,6 +173,7 @@ int main(int argc,char *argv[])
exit (-1); exit (-1);
} }
gst_object_ref (GST_OBJECT (disksrc));
gst_bin_remove (GST_BIN (bin), disksrc); gst_bin_remove (GST_BIN (bin), disksrc);
gst_object_destroy (GST_OBJECT (bin)); gst_object_destroy (GST_OBJECT (bin));

View file

@ -27,7 +27,7 @@ main (int argc,char *argv[])
gnome_init("Videotest","0.0.1",argc,argv); gnome_init("Videotest","0.0.1",argc,argv);
bin = gst_bin_new("bin"); bin = gst_pipeline_new("pipeline");
src = gst_elementfactory_make ("v4lsrc", "src"); src = gst_elementfactory_make ("v4lsrc", "src");
gtk_object_set(GTK_OBJECT(src),"format",9,NULL); gtk_object_set(GTK_OBJECT(src),"format",9,NULL);

View file

@ -1,8 +1,8 @@
SUBDIRS = sched eos SUBDIRS = sched eos
noinst_PROGRAMS = init loadall simplefake states caps queue registry \ noinst_PROGRAMS = init loadall simplefake states caps queue registry \
paranoia rip mp3encode autoplug props case4 markup load tee autoplug2 autoplug3 \ paranoia rip mp3encode autoplug props case4 markup load tee autoplug2 autoplug3 \
capsconnect padfactory autoplug4 capsconnect padfactory autoplug4 incsched reaping threadlock mp1vid
# we have nothing but apps here, we can do this safely # we have nothing but apps here, we can do this safely
LIBS += $(GST_LIBS) LIBS += $(GST_LIBS)

135
tests/incsched.c Normal file
View file

@ -0,0 +1,135 @@
#include <stdlib.h>
#include <gst/gst.h>
int main(int argc,char *argv[]) {
GstBin *thread, *bin;
GstElement *src, *identity, *sink, *identity2;
gst_init(&argc,&argv);
gst_info_set_categories(-1);
gst_debug_set_categories(-1);
g_print("\n\nConstructing stuff:\n");
thread = gst_pipeline_new("thread");
bin = gst_bin_new("bin");
src = gst_elementfactory_make("fakesrc","src");
identity = gst_elementfactory_make("identity","identity");
sink = gst_elementfactory_make("fakesink","sink");
identity2 = gst_elementfactory_make("identity","identity2");
g_print("\nAdding src to thread:\n");
gst_bin_add(thread,src);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nAdding identity to thread:\n");
gst_bin_add(thread,identity);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nRemoving identity from thread:\n");
gst_bin_remove(thread, identity);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nAdding identity to thread:\n");
gst_bin_add(thread,identity);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nConnecting src to identity:\n");
gst_element_connect(src,"src",identity,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nDisconnecting src from identity:\n");
gst_element_disconnect(src,"src",identity,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nConnecting src to identity:\n");
gst_element_connect(src,"src",identity,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nAdding sink to bin:\n");
gst_bin_add(bin,sink);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nAdding bin to thread:\n");
gst_bin_add(thread, GST_ELEMENT(bin));
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nConnecting identity to sink:\n");
gst_element_connect(identity,"src",sink,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nDisconnecting sink:\n");
gst_element_disconnect(identity,"src",sink,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nAdding identity2 to bin:\n");
gst_bin_add(bin, identity2);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nConnecting identity2 to sink\n");
gst_element_connect(identity2,"src",sink,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nConnecting identity to identity2\n");
gst_element_connect(identity,"src",identity2,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\n\nNow setting state from NULL to READY:\n");
gst_element_set_state(GST_ELEMENT(thread),GST_STATE_READY);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\n\nNow setting state from READY to PLAYING:\n");
gst_element_set_state(GST_ELEMENT(thread),GST_STATE_PLAYING);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\n\nIterating:\n");
gst_bin_iterate(thread);
g_print("\n\nNow setting state from PLAYING to READY:\n");
gst_element_set_state(GST_ELEMENT(thread),GST_STATE_READY);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\n\nNow setting state from READY to PLAYING:\n");
gst_element_set_state(GST_ELEMENT(thread),GST_STATE_PLAYING);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\n\nIterating:\n");
gst_bin_iterate(thread);
g_print("\n\nNow setting state from PLAYING to READY:\n");
gst_element_set_state(GST_ELEMENT(thread),GST_STATE_READY);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nDisconnecting identity from identity2:\n");
gst_element_disconnect(identity,"src",identity2,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nDisconnecting identity2 from sink:\n");
gst_element_disconnect(identity2,"src",sink,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\nConnecting identity to sink:\n");
gst_element_connect(identity,"src",sink,"sink");
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\n\nNow setting identity2 to NULL:\n");
gst_element_set_state(identity2,GST_STATE_NULL);
g_print("\nRemoving identity2 from bin:\n");
gst_bin_remove(bin, identity2);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\n\nNow setting state from READY to PLAYING:\n");
gst_element_set_state(GST_ELEMENT(thread),GST_STATE_PLAYING);
gst_schedule_show(GST_ELEMENT_SCHED(thread));
g_print("\n\nIterating:\n");
gst_bin_iterate(thread);
//return;
g_print("\n\nSetting EOS on fakesrc and iterating again:\n");
gtk_object_set(GTK_OBJECT(src),"eos",TRUE,NULL);
gst_bin_iterate(thread);
g_print("\n\nIterating:\n");
gst_bin_iterate(thread);
}

78
tests/mp1vid.c Normal file
View file

@ -0,0 +1,78 @@
#include <gst/gst.h>
GstElement *audiothread;
GstElement *audioqueue;
GstElement *audiodecode;
GstElement *audiosink;
void new_pad(GstElement *parse,GstPad *pad,GstElement *pipeline) {
if (!strncmp(gst_pad_get_name(pad), "audio_", 6)) {
fprintf(stderr,"have audio pad\n");
fprintf(stderr,"creating thread\n");
audiothread = gst_elementfactory_make("thread","audiothread");
gst_bin_add(GST_BIN(pipeline),audiothread);
fprintf(stderr,"creating queue\n");
audioqueue = gst_elementfactory_make("queue","audioqueue");
gst_bin_add(GST_BIN(audiothread),audioqueue);
gst_pad_connect(pad,gst_element_get_pad(audioqueue,"sink"));
fprintf(stderr,"creating decoder\n");
audiodecode = gst_elementfactory_make("mad","audiodecode");
gst_bin_add(GST_BIN(audiothread),audiodecode);
gst_element_connect(audioqueue,"src",audiodecode,"sink");
fprintf(stderr,"creating esdsink\n");
audiosink = gst_elementfactory_make("osssink","audiosink");
gst_bin_add(GST_BIN(audiothread),audiosink);
gst_element_connect(audiodecode,"src",audiosink,"sink");
fprintf(stderr,"setting state to PLAYING\n");
gst_element_set_state(audiothread,GST_STATE_PLAYING);
fprintf(stderr,"done dealing with new audio pad\n");
}
}
int main(int argc,char *argv[]) {
GstElement *pipeline, *sourcethread, *src, *parse;
int i;
gst_init(&argc,&argv);
pipeline = gst_pipeline_new("pipeline");
sourcethread = gst_elementfactory_make("thread","sourcethread");
src = gst_elementfactory_make("disksrc","src");
gtk_object_set(GTK_OBJECT(src),"location","/home/omega/media/AlienSong.mpg",NULL);
parse = gst_elementfactory_make("mpeg1parse","parse");
gtk_signal_connect(GTK_OBJECT(parse),"new_pad",
GTK_SIGNAL_FUNC(new_pad),pipeline);
gst_bin_add(GST_BIN(sourcethread),src);
gst_bin_add(GST_BIN(sourcethread),parse);
gst_element_connect(src,"src",parse,"sink");
gst_bin_add(GST_BIN(pipeline),sourcethread);
gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
gst_element_set_state(pipeline,GST_STATE_PLAYING);
sleep(1);
while (1) {
// sleep(1);
fprintf(stderr,"setting to PAUSED\n");
gst_element_set_state(pipeline,GST_STATE_PAUSED);fprintf(stderr,"paused... ");
// sleep(1);
fprintf(stderr,"setting to PLAYING\n");
gst_element_set_state(pipeline,GST_STATE_PLAYING);fprintf(stderr,"playing.\n");
}
// for (i=0;i<10;i++)
// while (1)
// gst_bin_iterate(GST_BIN(pipeline));
}

View file

@ -8,4 +8,4 @@ endif
SUBDIRS = $(GNOME_SUBDS) \ SUBDIRS = $(GNOME_SUBDS) \
helloworld helloworld2 \ helloworld helloworld2 \
queue queue2 queue3 queue4 \ queue queue2 queue3 queue4 \
launch thread xml plugins typefind launch thread xml plugins typefind mixer

View file

@ -2,94 +2,36 @@
#include <gnome.h> #include <gnome.h>
static void static void
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data) autoplug_have_size (GstElement *element, guint width, guint height,
GtkWidget *socket)
{ {
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data); gtk_widget_set_usize(socket,width,height);
*(gboolean *)data = TRUE;
} }
gboolean static void
idle_func (gpointer data) gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
{ {
return gst_bin_iterate (GST_BIN (data)); GstElement *osssink, *videosink;
}
static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element)
{
gboolean found = FALSE;
GstElement *typefind;
GstCaps *caps = NULL;
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
GST_ELEMENT_NAME(element), &found);
typefind = gst_elementfactory_make ("typefind", "typefind");
g_return_val_if_fail (typefind != NULL, FALSE);
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
gst_pad_connect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_add (bin, typefind);
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
// push a buffer... the have_type signal handler will set the found flag
gst_bin_iterate (bin);
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
gst_pad_disconnect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink"));
gst_bin_remove (bin, typefind);
gst_object_unref (GST_OBJECT (typefind));
return caps;
}
int main(int argc,char *argv[])
{
GstElement *disksrc, *osssink, *videosink;
GstElement *bin;
GtkWidget *appwindow; GtkWidget *appwindow;
GstCaps *srccaps;
GstElement *new_element; GstElement *new_element;
GstAutoplug *autoplug; GstAutoplug *autoplug;
GtkWidget *socket; GtkWidget *socket;
GstElement *autobin;
GstElement *disksrc;
GstElement *cache;
g_thread_init(NULL); GST_DEBUG (0,"GstPipeline: play have type\n");
gst_init(&argc,&argv);
gnome_init("autoplug","0.0.1", argc,argv);
if (argc != 2) { gst_element_set_state (pipeline, GST_STATE_PAUSED);
g_print("usage: %s <filename>\n", argv[0]);
exit(-1);
}
/* create a new bin to hold the elements */ disksrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source");
bin = gst_pipeline_new("pipeline"); autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
g_assert(bin != NULL); cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
/* create a disk reader */ // disconnect the typefind from the pipeline and remove it
disksrc = gst_elementfactory_make("disksrc", "disk_source"); gst_element_disconnect (cache, "src", typefind, "sink");
g_assert(disksrc != NULL); gst_bin_remove (GST_BIN (autobin), typefind);
gtk_object_set(GTK_OBJECT(disksrc),"location", argv[1],NULL);
gst_bin_add (GST_BIN (bin), disksrc);
srccaps = gst_play_typefind (GST_BIN (bin), disksrc);
if (!srccaps) {
g_print ("could not autoplug, unknown media type...\n");
exit (-1);
}
/* and an audio sink */ /* and an audio sink */
osssink = gst_elementfactory_make("osssink", "play_audio"); osssink = gst_elementfactory_make("osssink", "play_audio");
g_assert(osssink != NULL); g_assert(osssink != NULL);
@ -102,7 +44,7 @@ int main(int argc,char *argv[])
g_assert (autoplug != NULL); g_assert (autoplug != NULL);
new_element = gst_autoplug_to_renderers (autoplug, new_element = gst_autoplug_to_renderers (autoplug,
srccaps, caps,
videosink, videosink,
osssink, osssink,
NULL); NULL);
@ -112,42 +54,122 @@ int main(int argc,char *argv[])
exit (-1); exit (-1);
} }
gst_bin_remove (GST_BIN (bin), disksrc); gst_element_set_name (new_element, "new_element");
// FIXME hack, reparent the disksrc so the scheduler doesn't break
bin = gst_pipeline_new("pipeline");
gst_bin_add (GST_BIN (bin), disksrc); gst_bin_add (GST_BIN (autobin), new_element);
gst_bin_add (GST_BIN (bin), new_element);
gst_element_connect (disksrc, "src", new_element, "sink"); gtk_object_set (GTK_OBJECT (cache), "reset", TRUE, NULL);
appwindow = gnome_app_new("autoplug demo","autoplug demo"); gst_element_connect (cache, "src", new_element, "sink");
appwindow = gnome_app_new ("autoplug demo","autoplug demo");
socket = gtk_socket_new (); socket = gtk_socket_new ();
gtk_widget_show (socket); gtk_widget_show (socket);
gnome_app_set_contents(GNOME_APP(appwindow), gnome_app_set_contents (GNOME_APP (appwindow),
GTK_WIDGET (socket)); GTK_WIDGET (socket));
gtk_widget_realize (socket); gtk_widget_realize (socket);
gtk_socket_steal (GTK_SOCKET (socket), gtk_socket_steal (GTK_SOCKET (socket),
gst_util_get_int_arg (GTK_OBJECT (videosink), "xid")); gst_util_get_int_arg (GTK_OBJECT (videosink), "xid"));
gtk_widget_set_usize(socket,320,240);
gtk_widget_show_all(appwindow); gtk_widget_show_all (appwindow);
xmlSaveFile("xmlTest.gst", gst_xml_write(GST_ELEMENT(bin))); gtk_signal_connect (GTK_OBJECT (videosink), "have_size",
GTK_SIGNAL_FUNC (autoplug_have_size), socket);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
xmlSaveFile("xmlTest.gst", gst_xml_write (GST_ELEMENT (pipeline)));
}
gboolean
idle_func (gpointer data)
{
return gst_bin_iterate (GST_BIN (data));
}
static void
gst_play_cache_empty (GstElement *element, GstElement *pipeline)
{
GstElement *autobin;
GstElement *disksrc;
GstElement *cache;
GstElement *new_element;
fprintf (stderr, "have cache empty\n");
gst_element_set_state (pipeline, GST_STATE_PAUSED);
disksrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source");
autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
gst_element_disconnect (disksrc, "src", cache, "sink");
gst_element_disconnect (cache, "src", new_element, "sink");
gst_bin_remove (GST_BIN (autobin), cache);
gst_element_connect (disksrc, "src", new_element, "sink");
gst_element_set_state (pipeline, GST_STATE_PLAYING);
fprintf (stderr, "done with cache_empty\n");
}
int main(int argc,char *argv[])
{
GstElement *disksrc;
GstElement *pipeline;
GstElement *autobin;
GstElement *typefind;
GstElement *cache;
g_thread_init(NULL);
gst_init(&argc,&argv);
gnome_init("autoplug","0.0.1", argc,argv);
if (argc != 2) {
g_print("usage: %s <filename>\n", argv[0]);
exit(-1);
}
/* create a new pipeline to hold the elements */
pipeline = gst_pipeline_new("pipeline");
g_assert(pipeline != NULL);
/* create a disk reader */
disksrc = gst_elementfactory_make("disksrc", "disk_source");
g_assert(disksrc != NULL);
gtk_object_set(GTK_OBJECT(disksrc),"location", argv[1],NULL);
gst_bin_add (GST_BIN (pipeline), disksrc);
autobin = gst_bin_new ("autobin");
cache = gst_elementfactory_make ("autoplugcache", "cache");
gtk_signal_connect (GTK_OBJECT (cache), "cache_empty", GTK_SIGNAL_FUNC (gst_play_cache_empty), pipeline);
typefind = gst_elementfactory_make ("typefind", "typefind");
gtk_signal_connect (GTK_OBJECT (typefind), "have_type", GTK_SIGNAL_FUNC (gst_play_have_type), pipeline);
gst_bin_add (GST_BIN (autobin), cache);
gst_bin_add (GST_BIN (autobin), typefind);
gst_element_connect (cache, "src", typefind, "sink");
gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink");
gst_bin_add (GST_BIN( pipeline), autobin);
gst_element_connect (disksrc, "src", autobin, "sink");
/* start playing */ /* start playing */
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_PLAYING); gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING);
gtk_idle_add(idle_func, bin); gtk_idle_add (idle_func, pipeline);
gst_main ();
gst_main(); /* stop the pipeline */
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
/* stop the bin */ gst_object_unref (GST_OBJECT (pipeline));
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_NULL);
gst_pipeline_destroy(bin);
exit(0); exit(0);
} }

View file

@ -4,10 +4,13 @@
* demonstrates the adder plugin and the volume envelope plugin * demonstrates the adder plugin and the volume envelope plugin
* work in progress but do try it out * work in progress but do try it out
* *
* Latest change : 16/04/2001 * Latest change : 28/04/2001
* multiple input channels allowed * trying to adapt to incsched
* volume envelope adapted * delayed start for channels > 1
* Version : 0.3 * now works by quickhacking the
* adder plugin to set
* GST_ELEMENT_COTHREAD_STOPPING
* Version : 0.5
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -15,8 +18,10 @@
#include "mixer.h" #include "mixer.h"
#include <unistd.h> #include <unistd.h>
//#define WITH_BUG
//#define WITH_BUG2
//#define DEBUG //#define DEBUG
//#define AUTOPLUG /* define if you want autoplugging of input channels */
/* function prototypes */ /* function prototypes */
input_channel_t* create_input_channel (int id, char* location); input_channel_t* create_input_channel (int id, char* location);
@ -35,55 +40,50 @@ void eos(GstElement *element)
// playing = FALSE; // playing = FALSE;
} }
static void
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
{
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
*(gboolean *)data = TRUE;
}
static GstCaps* static GstCaps*
gst_play_typefind (GstBin *bin, GstElement *element) gst_play_typefind (GstBin *bin, GstElement *element)
{ {
gboolean found = FALSE;
GstElement *typefind; GstElement *typefind;
GstElement *pipeline;
GstCaps *caps = NULL; GstCaps *caps = NULL;
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n", GST_DEBUG (0,"GstPipeline: typefind for element \"%s\"\n",
GST_ELEMENT_NAME(element), &found); GST_ELEMENT_NAME(element));
pipeline = gst_pipeline_new ("autoplug_pipeline");
typefind = gst_elementfactory_make ("typefind", "typefind"); typefind = gst_elementfactory_make ("typefind", "typefind");
g_return_val_if_fail (typefind != NULL, FALSE); g_return_val_if_fail (typefind != NULL, FALSE);
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
gst_pad_connect (gst_element_get_pad (element, "src"), gst_pad_connect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink")); gst_element_get_pad (typefind, "sink"));
gst_bin_add (bin, typefind); gst_bin_add (bin, typefind);
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (bin));
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING); gst_element_set_state (pipeline, GST_STATE_PLAYING);
// push a buffer... the have_type signal handler will set the found flag // push a buffer... the have_type signal handler will set the found flag
gst_bin_iterate (bin); gst_bin_iterate (GST_BIN (pipeline));
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL); gst_element_set_state (pipeline, GST_STATE_NULL);
caps = gst_pad_get_caps (gst_element_get_pad (element, "src")); caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
gst_pad_disconnect (gst_element_get_pad (element, "src"), gst_pad_disconnect (gst_element_get_pad (element, "src"),
gst_element_get_pad (typefind, "sink")); gst_element_get_pad (typefind, "sink"));
gst_bin_remove (bin, typefind); gst_bin_remove (bin, typefind);
gst_bin_remove (GST_BIN (pipeline), GST_ELEMENT (bin));
gst_object_unref (GST_OBJECT (typefind)); gst_object_unref (GST_OBJECT (typefind));
gst_object_unref (GST_OBJECT (pipeline));
return caps; return caps;
} }
int main(int argc,char *argv[]) int main(int argc,char *argv[])
{ {
int i; int i, j;
int num_channels; int num_channels;
gboolean done;
char buffer[20]; char buffer[20];
@ -108,38 +108,41 @@ int main(int argc,char *argv[])
/* set up output channel and main bin */ /* set up output channel and main bin */
/* create adder */ /* create adder */
adder = gst_elementfactory_make("adder", "adderel"); adder = gst_elementfactory_make ("adder", "adderel");
/* create an audio sink */ /* create an audio sink */
audiosink = gst_elementfactory_make("esdsink", "play_audio"); audiosink = gst_elementfactory_make ("esdsink", "play_audio");
/* create main bin */ /* create main bin */
main_bin = gst_bin_new("bin"); main_bin = gst_pipeline_new("bin");
/* connect adder and output to bin */ /* connect adder and output to bin */
GST_INFO (0, "main: adding adder to bin");
gst_bin_add(GST_BIN(main_bin), adder); gst_bin_add (GST_BIN(main_bin), adder);
gst_bin_add(GST_BIN(main_bin), audiosink); GST_INFO (0, "main: adding audiosink to bin");
gst_bin_add (GST_BIN(main_bin), audiosink);
/* connect adder and audiosink */ /* connect adder and audiosink */
gst_pad_connect(gst_element_get_pad(adder,"src"), gst_pad_connect(gst_element_get_pad(adder,"src"),
gst_element_get_pad(audiosink,"sink")); gst_element_get_pad(audiosink,"sink"));
/* create input channels, add to bin and connect */ /* start looping */
input_channels = NULL; input_channels = NULL;
for (i = 1; i < argc; ++i) for (i = 1; i < argc; ++i)
{ {
printf ("Opening channel %d from file %s...\n", i, argv[i]); printf ("Opening channel %d from file %s...\n", i, argv[i]);
channel_in = create_input_channel (i, argv[i]); channel_in = create_input_channel (i, argv[i]);
input_channels = g_list_append (input_channels, channel_in); input_channels = g_list_append (input_channels, channel_in);
gst_bin_add(GST_BIN(main_bin), channel_in->pipe);
if (i > 1) gst_element_set_state (main_bin, GST_STATE_PAUSED);
gst_bin_add (GST_BIN(main_bin), channel_in->pipe);
/* request pads and connect to adder */ /* request pads and connect to adder */
GST_INFO (0, "requesting pad\n");
pad = gst_element_request_pad_by_name (adder, "sink%d"); pad = gst_element_request_pad_by_name (adder, "sink%d");
g_print ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad)); printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
sprintf (buffer, "channel%d", i); sprintf (buffer, "channel%d", i);
gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad); gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad);
@ -178,24 +181,32 @@ int main(int argc,char *argv[])
env_register_cp (channel_in->volenv, num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */ env_register_cp (channel_in->volenv, num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */
} }
env_register_cp (channel_in->volenv, num_channels * 10.0 , 1.0 / num_channels); /* to end level */ env_register_cp (channel_in->volenv, num_channels * 10.0 , 1.0 / num_channels); /* to end level */
xmlSaveFile("mixer.xml", gst_xml_write(GST_ELEMENT(main_bin)));
/* start playing */
gst_element_set_state(main_bin, GST_STATE_PLAYING);
// write out the schedule
gst_schedule_show(GST_ELEMENT_SCHED(main_bin));
playing = TRUE;
j = 0;
//printf ("main: start iterating from 0");
while (playing && j < 100)
{
// printf ("main: iterating %d\n", j);
gst_bin_iterate(GST_BIN(main_bin));
//fprintf(stderr,"after iterate()\n");
++j;
}
} }
printf ("main: all the channels are open\n");
/* sleep a few seconds doesn't seem to help anyway */ while (playing)
{
printf ("Sleeping a few seconds ...\n");
sleep (2);
printf ("Waking up ...\n");
/* start playing */
gst_element_set_state(main_bin, GST_STATE_PLAYING);
playing = TRUE;
while (playing) {
gst_bin_iterate(GST_BIN(main_bin)); gst_bin_iterate(GST_BIN(main_bin));
//fprintf(stderr,"after iterate()\n");
} }
/* stop the bin */ /* stop the bin */
gst_element_set_state(main_bin, GST_STATE_NULL); gst_element_set_state(main_bin, GST_STATE_NULL);
@ -228,11 +239,10 @@ create_input_channel (int id, char* location)
GstAutoplug *autoplug; GstAutoplug *autoplug;
GstCaps *srccaps; GstCaps *srccaps;
GstElement *new_element; GstElement *new_element;
GstElement *decoder;
#ifdef DEBUG GST_DEBUG (0, "c_i_p : creating channel with id %d for file %s\n",
printf ("DEBUG : c_i_p : creating channel with id %d for file %s\n",
id, location); id, location);
#endif
/* allocate channel */ /* allocate channel */
@ -245,23 +255,21 @@ create_input_channel (int id, char* location)
/* create channel */ /* create channel */
#ifdef DEBUG GST_DEBUG (0, "c_i_p : creating pipeline\n");
printf ("DEBUG : c_i_p : creating pipeline\n");
#endif
channel->pipe = gst_bin_new ("pipeline"); sprintf (buffer, "pipeline%d", id);
channel->pipe = gst_bin_new (buffer);
g_assert(channel->pipe != NULL); g_assert(channel->pipe != NULL);
/* create elements */ /* create elements */
#ifdef DEBUG GST_DEBUG(0, "c_i_p : creating disksrc\n");
printf ("DEBUG : c_i_p : creating disksrc\n");
#endif
sprintf (buffer, "disksrc%d", id); sprintf (buffer, "disksrc%d", id);
channel->disksrc = gst_elementfactory_make ("disksrc", buffer); channel->disksrc = gst_elementfactory_make ("disksrc", buffer);
g_assert(channel->disksrc != NULL); g_assert(channel->disksrc != NULL);
GST_DEBUG(0, "c_i_p : setting location\n");
gtk_object_set(GTK_OBJECT(channel->disksrc),"location", location, NULL); gtk_object_set(GTK_OBJECT(channel->disksrc),"location", location, NULL);
/* add disksrc to the bin before autoplug */ /* add disksrc to the bin before autoplug */
@ -286,8 +294,24 @@ create_input_channel (int id, char* location)
printf ("DEBUG : c_i_p : getting srccaps\n"); printf ("DEBUG : c_i_p : getting srccaps\n");
#endif #endif
#ifdef WITH_BUG
srccaps = gst_play_typefind (GST_BIN (channel->pipe), channel->disksrc); srccaps = gst_play_typefind (GST_BIN (channel->pipe), channel->disksrc);
#endif
#ifdef WITH_BUG2
{
GstElement *pipeline;
pipeline = gst_pipeline_new ("autoplug_pipeline");
gst_bin_add (GST_BIN (pipeline), channel->pipe);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_bin_remove (GST_BIN (pipeline), channel->pipe);
}
#endif
#ifdef AUTOPLUG
if (!srccaps) { if (!srccaps) {
g_print ("could not autoplug, unknown media type...\n"); g_print ("could not autoplug, unknown media type...\n");
exit (-1); exit (-1);
@ -311,7 +335,24 @@ create_input_channel (int id, char* location)
g_print ("could not autoplug, no suitable codecs found...\n"); g_print ("could not autoplug, no suitable codecs found...\n");
exit (-1); exit (-1);
} }
#else
new_element = gst_bin_new ("autoplug_bin");
/* static plug, use mad plugin and assume mp3 input */
decoder = gst_elementfactory_make ("mad", "mpg123");
gst_bin_add (GST_BIN (new_element), decoder);
gst_element_add_ghost_pad (new_element,
gst_element_get_pad (decoder, "sink"), "sink");
gst_element_add_ghost_pad (new_element,
gst_element_get_pad (decoder, "src"), "src_00");
#endif
xmlSaveFile ("mixer.gst", gst_xml_write (new_element));
gst_bin_add (GST_BIN(channel->pipe), channel->volenv); gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
gst_bin_add (GST_BIN (channel->pipe), new_element); gst_bin_add (GST_BIN (channel->pipe), new_element);

View file

@ -0,0 +1,18 @@
SUBDIRS =
testprogs = object element pad element_pad bin thread
object_SOURCES = object.c mem.c
element_SOURCES = element.c mem.c
pad_SOURCES = pad.c mem.c
element_pad_SOURCES = element_pad.c mem.c
bin_SOURCES = bin.c mem.c
thread_SOURCES = thread.c mem.c
TESTS = $(testprogs)
check_PROGRAMS = $(testprogs)
# we have nothing but apps here, we can do this safely
LIBS += $(GST_LIBS)
CFLAGS += $(GST_CFLAGS)

View file

@ -0,0 +1,272 @@
#include <gst/gst.h>
#define ITERS 100000
#include <stdlib.h>
#include "mem.h"
static GstElement*
create_bin (void)
{
GstElement *bin;
GstElement *element;
bin = gst_bin_new ("testbin");
element = gst_element_new ();
gst_element_set_name (element, "test1");
gst_bin_add (GST_BIN (bin), element);
element = gst_element_new ();
gst_element_set_name (element, "test2");
gst_bin_add (GST_BIN (bin), element);
return bin;
}
static GstElement*
create_bin_ghostpads (void)
{
GstElement *bin;
GstElement *element1, *element2;
bin = gst_bin_new ("testbin");
element1 = gst_element_new ();
gst_element_set_name (element1, "test1");
gst_element_add_pad (element1, gst_pad_new ("src1", GST_PAD_SRC));
gst_bin_add (GST_BIN (bin), element1);
element2 = gst_element_new ();
gst_element_set_name (element2, "test2");
gst_element_add_pad (element2, gst_pad_new ("sink1", GST_PAD_SINK));
gst_bin_add (GST_BIN (bin), element2);
gst_element_connect (element1, "src1", element2, "sink1");
gst_element_add_ghost_pad (bin, gst_element_get_pad (element2, "sink1"), "ghost_sink");
return bin;
}
static void
add_remove_test1 (void)
{
GstElement *bin;
GstElement *element;
bin = gst_bin_new ("testbin");
element = gst_element_new ();
gst_element_set_name (element, "test1");
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
gst_bin_remove (GST_BIN (bin), element);
gst_object_unref (GST_OBJECT (bin));
}
static void
add_remove_test2 (void)
{
GstElement *bin;
GstElement *element;
bin = gst_bin_new ("testbin");
element = gst_element_new ();
gst_element_set_name (element, "test1");
gst_object_ref (GST_OBJECT (element));
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
gst_bin_remove (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_DESTROYED (element));
gst_object_destroy (GST_OBJECT (element));
g_assert (GST_OBJECT_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (bin));
}
static void
add_remove_test3 (void)
{
GstElement *bin;
GstElement *element;
bin = gst_bin_new ("testbin");
element = gst_element_new ();
gst_element_set_name (element, "test1");
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
gst_object_destroy (GST_OBJECT (element));
g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
gst_object_unref (GST_OBJECT (bin));
}
static void
add_remove_test4 (void)
{
GstElement *bin, *bin2;
GstElement *element;
bin = gst_bin_new ("testbin");
element = gst_element_new ();
gst_element_set_name (element, "test1");
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
bin2 = create_bin ();
g_assert (GST_OBJECT_FLOATING (bin2));
gst_bin_add (GST_BIN (bin), bin2);
g_assert (!GST_OBJECT_FLOATING (bin2));
gst_object_destroy (GST_OBJECT (bin2));
g_assert (gst_bin_get_by_name (GST_BIN (bin), "testbin") == NULL);
gst_object_destroy (GST_OBJECT (element));
g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
gst_object_unref (GST_OBJECT (bin));
}
int
main (int argc, gchar *argv[])
{
GstElement *bin;
long usage1;
gint i, iters;
gst_init (&argc, &argv);
if (argc == 2)
iters = atoi (argv[1]);
else
iters = ITERS;
g_print ("starting test\n");
usage1 = vmsize();
bin = gst_bin_new ("somebin");
gst_object_unref (GST_OBJECT (bin));
g_print ("create/unref new bin %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/unref %d bins %ld\n", iters, vmsize()-usage1);
bin = gst_bin_new ("somebin");
g_assert (GST_OBJECT_FLOATING (bin));
gst_object_ref (GST_OBJECT (bin));
gst_object_sink (GST_OBJECT (bin));
g_assert (!GST_OBJECT_FLOATING (bin));
gst_object_unref (GST_OBJECT (bin));
g_print ("create/ref/sink/unref new bin %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_object_sink (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/ref/sink/unref %d bins %ld\n", iters, vmsize()-usage1);
bin = gst_bin_new ("somebin");
g_assert (!GST_OBJECT_DESTROYED (bin));
gst_object_destroy (GST_OBJECT (bin));
g_assert (GST_OBJECT_DESTROYED (bin));
gst_object_unref (GST_OBJECT (bin));
g_print ("create/destroy/unref new bin %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_destroy (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/destroy/unref %d bin %ld\n", iters, vmsize()-usage1);
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
g_print ("create/ref/unref/unref new bin %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/ref/unref/unref %d bin %ld\n", iters, vmsize()-usage1);
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_object_destroy (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
g_print ("craete/ref/destroy/unref/unref new bin %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_object_destroy (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
}
g_print ("craete/ref/destroy/unref/unref %d bins %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_element_set_name (bin, "testing123");
gst_object_destroy (GST_OBJECT (bin));
gst_element_set_name (bin, "testing123");
gst_object_unref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
}
g_print ("craete/ref/destroy/unref/unref %d bins with name %ld\n", iters, vmsize()-usage1);
bin = gst_bin_new ("somebin");
for (i=0; i<iters;i++) {
gst_element_set_name (bin, "testing");
}
gst_object_unref (GST_OBJECT (bin));
g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = create_bin();
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/unref %d bin with children %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters/2;i++) {
bin = create_bin_ghostpads();
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/unref %d bin with children and ghostpads %ld\n", iters/2, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test1();
}
g_print ("add/remove test1 %d in bin %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test2();
}
g_print ("add/remove test2 %d in bin %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test3();
}
g_print ("add/destroy/remove test3 %d in bin %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test4();
}
g_print ("add/destroy/remove test4 %d in bin %ld\n", iters, vmsize()-usage1);
g_print ("leaked: %ld\n", vmsize()-usage1);
return (vmsize()-usage1 ? -1 : 0);
}

View file

@ -0,0 +1,116 @@
#include <gst/gst.h>
#define ITERS 100000
#include <stdlib.h>
#include "mem.h"
int
main (int argc, gchar *argv[])
{
GstElement *element;
long usage1;
gint i, iters;
gst_init (&argc, &argv);
if (argc == 2)
iters = atoi (argv[1]);
else
iters = ITERS;
g_print ("starting test\n");
usage1 = vmsize();
element = gst_element_new ();
gst_object_unref (GST_OBJECT (element));
g_print ("create/unref new element %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_unref (GST_OBJECT (element));
}
g_print ("create/unref %d elements %ld\n", iters, vmsize()-usage1);
element = gst_element_new ();
g_assert (GST_OBJECT_FLOATING (element));
gst_object_ref (GST_OBJECT (element));
gst_object_sink (GST_OBJECT (element));
g_assert (!GST_OBJECT_FLOATING (element));
gst_object_unref (GST_OBJECT (element));
g_print ("create/ref/sink/unref new element %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_object_sink (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
}
g_print ("create/ref/sink/unref %d elements %ld\n", iters, vmsize()-usage1);
element = gst_element_new ();
g_assert (!GST_OBJECT_DESTROYED (element));
gst_object_destroy (GST_OBJECT (element));
g_assert (GST_OBJECT_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
g_print ("create/destroy/unref new element %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_destroy (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
}
g_print ("create/destroy/unref %d element %ld\n", iters, vmsize()-usage1);
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
g_print ("create/ref/unref/unref new element %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
}
g_print ("create/ref/unref/unref %d element %ld\n", iters, vmsize()-usage1);
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_object_destroy (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
g_print ("craete/ref/destroy/unref/unref new element %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_object_destroy (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
}
g_print ("craete/ref/destroy/unref/unref %d elements %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_element_set_name (element, "testing123");
gst_object_destroy (GST_OBJECT (element));
gst_element_set_name (element, "testing123");
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
}
g_print ("craete/ref/destroy/unref/unref %d elements with name %ld\n", iters, vmsize()-usage1);
element = gst_element_new ();
for (i=0; i<iters;i++) {
gst_element_set_name (element, "testing");
}
gst_object_unref (GST_OBJECT (element));
g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
g_print ("leaked: %ld\n", vmsize()-usage1);
return (vmsize()-usage1 ? -1 : 0);
}

View file

@ -0,0 +1,134 @@
#include <gst/gst.h>
#define ITERS 100000
#include <stdlib.h>
#include "mem.h"
static GstElement*
create_element (gchar *padname, GstPadDirection dir)
{
GstElement *element;
GstPad *pad;
element = gst_element_new ();
pad = gst_pad_new (padname, dir);
gst_element_add_pad (element, pad);
return element;
}
int
main (int argc, gchar *argv[])
{
GstElement *element;
GstElement *element2;
GstPad *pad;
long usage1;
gint i, iters;
gst_init (&argc, &argv);
if (argc == 2)
iters = atoi (argv[1]);
else
iters = ITERS;
g_print ("starting element with pad test with %d iterations\n", iters);
usage1 = vmsize();
element = create_element ("sink", GST_PAD_SINK);
pad = gst_element_get_pad (element, "sink");
g_assert (GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_FLOATING (pad));
g_assert (gst_pad_get_parent (pad) == element);
gst_object_unref (GST_OBJECT (element));
g_print ("create/addpad/unref new element %ld\n", vmsize()-usage1);
for (i=0; i<iters; i++) {
element = create_element ("sink", GST_PAD_SINK);
gst_object_unref (GST_OBJECT (element));
}
g_print ("create/addpad/unref %d elements %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters/2; i++) {
element = create_element ("sink", GST_PAD_SINK);
element2 = create_element ("src", GST_PAD_SRC);
gst_element_connect (element, "sink", element2, "src");
g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element, "sink")));
gst_object_unref (GST_OBJECT (element));
g_assert (!GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
gst_object_unref (GST_OBJECT (element2));
}
g_print ("create/connect/unref %d elements %ld\n", iters/2, vmsize()-usage1);
for (i=0; i<iters/2; i++) {
element = create_element ("sink", GST_PAD_SINK);
element2 = create_element ("src", GST_PAD_SRC);
gst_element_connect (element, "sink", element2, "src");
g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
g_assert (GST_PAD_CONNECTED (gst_element_get_pad (element, "sink")));
gst_object_destroy (GST_OBJECT (element));
g_assert (GST_OBJECT_DESTROYED (element));
g_assert (!GST_PAD_CONNECTED (gst_element_get_pad (element2, "src")));
gst_object_unref (GST_OBJECT (element2));
gst_object_unref (GST_OBJECT (element));
}
g_print ("create/connect/destroy %d elements %ld\n", iters/2, vmsize()-usage1);
element = create_element ("sink", GST_PAD_SINK);
pad = gst_element_get_pad (element, "sink");
gst_element_remove_pad (element, pad);
g_assert (gst_element_get_pad (element, "sink") == NULL);
g_print ("pad removal ok %ld\n", vmsize()-usage1);
for (i=0; i<iters/2; i++) {
element = create_element ("sink", GST_PAD_SINK);
pad = gst_element_get_pad (element, "sink");
gst_element_remove_pad (element, pad);
gst_object_unref (GST_OBJECT (element));
}
g_print ("pad removal loop %d %ld\n", iters/2, vmsize()-usage1);
for (i=0; i<iters/2; i++) {
element = create_element ("sink", GST_PAD_SINK);
pad = gst_element_get_pad (element, "sink");
gst_object_ref (GST_OBJECT (pad));
gst_element_remove_pad (element, pad);
g_assert (gst_pad_get_parent (pad) == NULL);
gst_object_unref (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (element));
}
g_print ("pad removal and test loop %d %ld\n", iters/2, vmsize()-usage1);
element = create_element ("sink", GST_PAD_SINK);
pad = gst_element_get_pad (element, "sink");
gst_object_destroy (GST_OBJECT (element));
g_assert (GST_OBJECT_DESTROYED (element));
g_assert (gst_element_get_pad (element, "sink") == NULL);
gst_object_unref (GST_OBJECT (element));
g_print ("pad destroy/removal ok %ld\n", vmsize()-usage1);
for (i=0; i<iters/2; i++) {
element = create_element ("sink", GST_PAD_SINK);
pad = gst_element_get_pad (element, "sink");
gst_object_destroy (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
}
g_print ("pad destroy/removal loop %d %ld\n", iters/2, vmsize()-usage1);
for (i=0; i<iters/2; i++) {
element = create_element ("sink", GST_PAD_SINK);
pad = gst_element_get_pad (element, "sink");
gst_object_destroy (GST_OBJECT (pad));
g_assert (gst_element_get_pad (element, "sink") == NULL);
gst_object_unref (GST_OBJECT (element));
}
g_print ("pad destroy loop %d %ld\n", iters/2, vmsize()-usage1);
g_print ("leaked: %ld\n", vmsize()-usage1);
return (vmsize()-usage1 ? -1 : 0);
}

View file

@ -0,0 +1,22 @@
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int vmsize() {
int pid,fd,size,i,mem;
char filename[17], buf[256], *ptr, *end;
pid = getpid();
snprintf(filename,17,"/proc/%d/stat",pid);
fd = open(filename,O_RDONLY);
size = read(fd,buf,240);
ptr = buf;
for (i=0;i<22;i++)
ptr = (char *)strchr(ptr,' ') + 1;
end = (char *)strchr(ptr,' ');
*end = 0;
sscanf(ptr,"%d",&mem);
close(fd);
return mem;
}

View file

@ -0,0 +1 @@
int vmsize();

View file

@ -0,0 +1,156 @@
#include <gst/gst.h>
#define ITERS 100000
#include <stdlib.h>
#include "mem.h"
int
main (int argc, gchar *argv[])
{
GstObject *object, *object2;
long usage1;
gint i, iters;
gst_init (&argc, &argv);
if (argc == 2)
iters = atoi (argv[1]);
else
iters = ITERS;
g_print ("starting test with %d iterations\n", iters);
usage1 = vmsize();
object = gst_object_new ();
gst_object_unref (object);
g_print ("create/unref new object %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
object = gst_object_new ();
gst_object_unref (object);
}
g_print ("create/unref %d object %ld\n", iters, vmsize()-usage1);
object = gst_object_new ();
g_assert (GST_OBJECT_FLOATING (object));
gst_object_ref (object);
gst_object_sink (object);
g_assert (!GST_OBJECT_FLOATING (object));
gst_object_unref (object);
g_print ("create/ref/sink/unref new object %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
object = gst_object_new ();
gst_object_ref (object);
gst_object_sink (object);
gst_object_unref (object);
}
g_print ("create/ref/sink/unref %d object %ld\n", iters, vmsize()-usage1);
object = gst_object_new ();
g_assert (!GST_OBJECT_DESTROYED (object));
gst_object_destroy (object);
g_assert (GST_OBJECT_DESTROYED (object));
gst_object_unref (object);
g_print ("create/destroy/unref new object %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
object = gst_object_new ();
gst_object_destroy (object);
gst_object_unref (object);
}
g_print ("destroy/unref %d object %ld\n", iters, vmsize()-usage1);
object = gst_object_new ();
gst_object_ref (object);
gst_object_unref (object);
gst_object_unref (object);
g_print ("create/ref/unref/unref new object %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
object = gst_object_new ();
gst_object_ref (object);
gst_object_unref (object);
gst_object_unref (object);
}
g_print ("create/ref/unref/unref %d object %ld\n", iters, vmsize()-usage1);
object = gst_object_new ();
gst_object_ref (object);
gst_object_destroy (object);
gst_object_unref (object);
gst_object_unref (object);
g_print ("create/ref/destroy/unref/unref new object %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
object = gst_object_new ();
gst_object_ref (object);
gst_object_destroy (object);
gst_object_unref (object);
gst_object_unref (object);
}
g_print ("create/ref/destroy/unref/unref %d object %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
object = gst_object_new ();
gst_object_ref (object);
gst_object_set_name (object, "testing123");
gst_object_destroy (object);
gst_object_set_name (object, "testing123");
gst_object_unref (object);
gst_object_unref (object);
}
g_print ("create/ref/destroy/unref/unref %d object with name %ld\n", iters, vmsize()-usage1);
object = gst_object_new ();
for (i=0; i<iters;i++) {
gst_object_set_name (object, "testing");
}
gst_object_unref (object);
g_print ("create/set name/unref %d object %ld\n", iters, vmsize()-usage1);
object = gst_object_new ();
object2 = gst_object_new ();
g_assert (GST_OBJECT_FLOATING (object));
g_assert (GST_OBJECT_FLOATING (object2));
gst_object_set_parent (object, object2);
g_assert (GST_OBJECT_FLOATING (object2));
g_assert (!GST_OBJECT_FLOATING (object));
g_print ("parentage flags set_parent ok %ld\n", vmsize()-usage1);
gst_object_ref (object);
gst_object_unparent (object);
g_assert (GST_OBJECT_FLOATING (object2));
g_assert (!GST_OBJECT_FLOATING (object));
g_assert (gst_object_get_parent (object) == NULL);
g_print ("parentage flags unparent ok %ld\n", vmsize()-usage1);
gst_object_set_parent (object, object2);
g_assert (GST_OBJECT_FLOATING (object2));
g_assert (!GST_OBJECT_FLOATING (object));
g_assert (gst_object_get_parent (object) == object2);
gst_object_destroy (object);
g_assert (GST_OBJECT_DESTROYED (object));
g_assert (!GST_OBJECT_FLOATING (object));
g_assert (gst_object_get_parent (object) == NULL);
gst_object_unref (object);
g_print ("parentage flags destroy ok %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
object = gst_object_new ();
object2 = gst_object_new ();
gst_object_set_parent (object2, object);
gst_object_unref (object);
gst_object_unref (object2);
}
g_print ("create/unref %d 2 parented objects %ld\n", iters, vmsize()-usage1);
g_print ("leaked: %ld\n", vmsize()-usage1);
return (vmsize()-usage1 ? -1 : 0);
}

View file

@ -0,0 +1,223 @@
#include <gst/gst.h>
#define ITERS 100000
#include <stdlib.h>
#include "mem.h"
int
main (int argc, gchar *argv[])
{
GstPad *pad;
GstPad *pad2;
GstPadTemplate *padtempl;
long usage1;
gint i, iters;
gst_init (&argc, &argv);
if (argc == 2)
iters = atoi (argv[1]);
else
iters = ITERS;
g_print ("starting pad test\n");
usage1 = vmsize();
pad = gst_pad_new ("padname", GST_PAD_SINK);
gst_object_unref (GST_OBJECT (pad));
g_print ("create/unref new pad %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
pad = gst_pad_new ("padname", GST_PAD_SINK);
gst_object_unref (GST_OBJECT (pad));
}
g_print ("create/unref %d pads %ld\n", iters, vmsize()-usage1);
pad = gst_pad_new ("padname", GST_PAD_SINK);
g_assert (GST_OBJECT_FLOATING (pad));
gst_object_ref (GST_OBJECT (pad));
gst_object_sink (GST_OBJECT (pad));
g_assert (!GST_OBJECT_FLOATING (pad));
gst_object_unref (GST_OBJECT (pad));
g_print ("create/ref/sink/unref new pad %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
pad = gst_pad_new ("padname", GST_PAD_SINK);
gst_object_ref (GST_OBJECT (pad));
gst_object_sink (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad));
}
g_print ("create/ref/sink/unref %d pads %ld\n", iters, vmsize()-usage1);
pad = gst_pad_new ("padname", GST_PAD_SINK);
g_assert (!GST_OBJECT_DESTROYED (pad));
gst_object_destroy (GST_OBJECT (pad));
g_assert (GST_OBJECT_DESTROYED (pad));
gst_object_unref (GST_OBJECT (pad));
g_print ("create/destroy/unref pad %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
pad = gst_pad_new ("padname", GST_PAD_SINK);
gst_object_destroy (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad));
}
g_print ("create/destroy/unref %d pads %ld\n", iters, vmsize()-usage1);
pad = gst_pad_new ("padname", GST_PAD_SINK);
gst_object_ref (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad));
g_print ("create/ref/unref/unref pad %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
pad = gst_pad_new ("padname", GST_PAD_SINK);
gst_object_ref (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad));
}
g_print ("create/ref/unref/unref %d pads %ld\n", iters, vmsize()-usage1);
pad = gst_pad_new ("padname", GST_PAD_SINK);
gst_object_ref (GST_OBJECT (pad));
gst_object_destroy (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad));
g_print ("create/ref/destroy/unref/unref pad %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
pad = gst_pad_new ("padname", GST_PAD_SINK);
gst_object_ref (GST_OBJECT (pad));
gst_object_destroy (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad));
}
g_print ("create/ref/destroy/unref/unref %d pads %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
pad = gst_pad_new ("padname", GST_PAD_SINK);
gst_object_ref (GST_OBJECT (pad));
gst_pad_set_name (pad, "testing123");
gst_object_destroy (GST_OBJECT (pad));
gst_pad_set_name (pad, "testing123");
gst_object_unref (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad));
}
g_print ("create/ref/destroy/unref/unref %d pads %ld with name\n", iters, vmsize()-usage1);
pad = gst_pad_new ("padname", GST_PAD_SINK);
for (i=0; i<iters;i++) {
gst_pad_set_name (pad, "testing");
}
gst_object_unref (GST_OBJECT (pad));
g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
pad = gst_pad_new ("padname", GST_PAD_SINK);
pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
gst_pad_connect (pad2, pad);
g_assert (GST_PAD_CONNECTED (pad));
g_assert (GST_PAD_CONNECTED (pad2));
gst_pad_disconnect (pad2, pad);
g_assert (!GST_PAD_CONNECTED (pad));
g_assert (!GST_PAD_CONNECTED (pad2));
g_print ("connect/disconnect pad %ld\n", vmsize()-usage1);
gst_pad_connect (pad, pad2);
g_assert (GST_PAD_CONNECTED (pad));
g_assert (GST_PAD_CONNECTED (pad2));
gst_pad_disconnect (pad, pad2);
g_assert (!GST_PAD_CONNECTED (pad));
g_assert (!GST_PAD_CONNECTED (pad2));
g_print ("connect/disconnect pad wrong direction %ld\n", vmsize()-usage1);
gst_object_unref (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad2));
for (i=0; i<iters;i++) {
pad = gst_pad_new ("padname", GST_PAD_SINK);
pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
gst_pad_connect (pad2, pad);
gst_pad_disconnect (pad2, pad);
gst_pad_connect (pad, pad2);
gst_pad_disconnect (pad, pad2);
gst_object_unref (GST_OBJECT (pad));
gst_object_unref (GST_OBJECT (pad2));
}
g_print ("connect/disconnect %d pads %ld\n", iters, vmsize()-usage1);
pad = gst_pad_new ("padname", GST_PAD_SINK);
pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
gst_pad_connect (pad2, pad);
g_assert (GST_PAD_CONNECTED (pad2));
g_assert (GST_PAD_CONNECTED (pad));
gst_object_unref (GST_OBJECT (pad2));
g_assert (!GST_PAD_CONNECTED (pad));
g_assert (!GST_OBJECT_DESTROYED (pad));
gst_object_unref (GST_OBJECT (pad));
pad = gst_pad_new ("padname", GST_PAD_SINK);
pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
gst_pad_connect (pad2, pad);
g_assert (GST_PAD_CONNECTED (pad2));
g_assert (GST_PAD_CONNECTED (pad));
gst_object_unref (GST_OBJECT (pad));
g_assert (!GST_PAD_CONNECTED (pad2));
g_assert (!GST_OBJECT_DESTROYED (pad2));
gst_object_unref (GST_OBJECT (pad2));
g_print ("pad unref effects on connect pad ok %ld\n", vmsize()-usage1);
pad = gst_pad_new ("padname", GST_PAD_SINK);
pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
gst_pad_connect (pad2, pad);
g_assert (GST_PAD_CONNECTED (pad2));
g_assert (GST_PAD_CONNECTED (pad));
gst_object_destroy (GST_OBJECT (pad2));
g_assert (GST_OBJECT_DESTROYED (pad2));
g_assert (!GST_OBJECT_DESTROYED (pad));
g_assert (!GST_PAD_CONNECTED (pad));
gst_object_unref (GST_OBJECT (pad2));
g_assert (!GST_OBJECT_DESTROYED (pad));
g_assert (!GST_PAD_CONNECTED (pad));
gst_object_unref (GST_OBJECT (pad));
pad = gst_pad_new ("padname", GST_PAD_SINK);
pad2 = gst_pad_new ("padname2", GST_PAD_SRC);
gst_pad_connect (pad2, pad);
g_assert (GST_PAD_CONNECTED (pad2));
g_assert (GST_PAD_CONNECTED (pad));
gst_object_destroy (GST_OBJECT (pad));
g_assert (GST_OBJECT_DESTROYED (pad));
g_assert (!GST_OBJECT_DESTROYED (pad2));
g_assert (!GST_PAD_CONNECTED (pad2));
gst_object_unref (GST_OBJECT (pad));
g_assert (!GST_OBJECT_DESTROYED (pad2));
g_assert (!GST_PAD_CONNECTED (pad2));
gst_object_unref (GST_OBJECT (pad2));
g_print ("pad destroy effects on connect pad ok %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
padtempl = gst_padtemplate_new ("sink%d", GST_PAD_SINK, GST_PAD_SOMETIMES, NULL);
gst_object_unref (GST_OBJECT (padtempl));
}
g_print ("%d padtemplates create/unref %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
padtempl = gst_padtemplate_new ("sink%d", GST_PAD_SINK, GST_PAD_SOMETIMES, NULL);
pad = gst_pad_new_from_template (padtempl, "sink1");
gst_object_unref (GST_OBJECT (pad));
}
g_print ("%d pads create/unref from padtemplate %ld\n", iters, vmsize()-usage1);
g_print ("leaked: %ld\n", vmsize()-usage1);
return vmsize()-usage1;
}

View file

@ -0,0 +1,281 @@
#include <gst/gst.h>
#define ITERS 100000
#include <stdlib.h>
#include "mem.h"
static GstElement*
create_thread (void)
{
GstElement *thread;
GstElement *element;
thread = gst_thread_new ("testthread");
element = gst_element_new ();
gst_element_set_name (element, "test1");
gst_bin_add (GST_BIN (thread), element);
element = gst_element_new ();
gst_element_set_name (element, "test2");
gst_bin_add (GST_BIN (thread), element);
return thread;
}
static GstElement*
create_thread_ghostpads (void)
{
GstElement *thread;
GstElement *element1, *element2;
thread = gst_thread_new ("testthread");
element1 = gst_element_new ();
gst_element_set_name (element1, "test1");
gst_element_add_pad (element1, gst_pad_new ("src1", GST_PAD_SRC));
gst_bin_add (GST_BIN (thread), element1);
element2 = gst_element_new ();
gst_element_set_name (element2, "test2");
gst_element_add_pad (element2, gst_pad_new ("sink1", GST_PAD_SINK));
gst_bin_add (GST_BIN (thread), element2);
gst_element_connect (element1, "src1", element2, "sink1");
gst_element_add_ghost_pad (thread, gst_element_get_pad (element2, "sink1"), "sink1");
return thread;
}
static void
add_remove_test1 (void)
{
GstElement *thread;
GstElement *element;
thread = gst_thread_new ("testthread");
element = gst_element_new ();
gst_element_set_name (element, "test1");
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (thread), element);
g_assert (!GST_OBJECT_FLOATING (element));
gst_bin_remove (GST_BIN (thread), element);
gst_object_unref (GST_OBJECT (thread));
}
static void
add_remove_test2 (void)
{
GstElement *thread;
GstElement *element;
thread = gst_thread_new ("testthread");
element = gst_element_new ();
gst_element_set_name (element, "test1");
gst_object_ref (GST_OBJECT (element));
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (thread), element);
g_assert (!GST_OBJECT_FLOATING (element));
gst_bin_remove (GST_BIN (thread), element);
g_assert (!GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_DESTROYED (element));
gst_object_destroy (GST_OBJECT (element));
g_assert (GST_OBJECT_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (thread));
}
static void
add_remove_test3 (void)
{
GstElement *thread;
GstElement *element;
thread = gst_thread_new ("testthread");
element = gst_element_new ();
gst_element_set_name (element, "test1");
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (thread), element);
g_assert (!GST_OBJECT_FLOATING (element));
gst_object_destroy (GST_OBJECT (element));
g_assert (gst_bin_get_by_name (GST_BIN (thread), "test1") == NULL);
gst_object_unref (GST_OBJECT (thread));
}
static void
add_remove_test4 (void)
{
GstElement *thread, *thread2;
GstElement *element;
thread = gst_thread_new ("testthread");
element = gst_element_new ();
gst_element_set_name (element, "test1");
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (thread), element);
g_assert (!GST_OBJECT_FLOATING (element));
thread2 = create_thread ();
g_assert (GST_OBJECT_FLOATING (thread2));
gst_bin_add (GST_BIN (thread), thread2);
g_assert (!GST_OBJECT_FLOATING (thread2));
gst_object_destroy (GST_OBJECT (thread2));
g_assert (gst_bin_get_by_name (GST_BIN (thread), "testthread") == NULL);
gst_object_destroy (GST_OBJECT (element));
g_assert (gst_bin_get_by_name (GST_BIN (thread), "test1") == NULL);
gst_object_unref (GST_OBJECT (thread));
}
int
main (int argc, gchar *argv[])
{
GstElement *thread, *element;
long usage1;
gint i, iters;
gst_init (&argc, &argv);
if (argc == 2)
iters = atoi (argv[1]);
else
iters = ITERS;
g_print ("starting test\n");
usage1 = vmsize();
thread = gst_thread_new ("somethread");
gst_object_unref (GST_OBJECT (thread));
g_print ("create/unref new thread %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
thread = gst_thread_new ("somethread");
gst_object_unref (GST_OBJECT (thread));
}
g_print ("create/unref %d threads %ld\n", iters, vmsize()-usage1);
thread = gst_thread_new ("somethread");
g_assert (GST_OBJECT_FLOATING (thread));
gst_object_ref (GST_OBJECT (thread));
gst_object_sink (GST_OBJECT (thread));
g_assert (!GST_OBJECT_FLOATING (thread));
gst_object_unref (GST_OBJECT (thread));
g_print ("create/ref/sink/unref new thread %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
thread = gst_thread_new ("somethread");
gst_object_ref (GST_OBJECT (thread));
gst_object_sink (GST_OBJECT (thread));
gst_object_unref (GST_OBJECT (thread));
}
g_print ("create/ref/sink/unref %d threads %ld\n", iters, vmsize()-usage1);
thread = gst_thread_new ("somethread");
g_assert (!GST_OBJECT_DESTROYED (thread));
gst_object_destroy (GST_OBJECT (thread));
g_assert (GST_OBJECT_DESTROYED (thread));
gst_object_unref (GST_OBJECT (thread));
g_print ("create/destroy/unref new thread %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
thread = gst_thread_new ("somethread");
gst_object_destroy (GST_OBJECT (thread));
gst_object_unref (GST_OBJECT (thread));
}
g_print ("create/destroy/unref %d thread %ld\n", iters, vmsize()-usage1);
thread = gst_thread_new ("somethread");
gst_object_ref (GST_OBJECT (thread));
gst_object_unref (GST_OBJECT (thread));
gst_object_unref (GST_OBJECT (thread));
g_print ("create/ref/unref/unref new thread %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
thread = gst_thread_new ("somethread");
gst_object_ref (GST_OBJECT (thread));
gst_object_unref (GST_OBJECT (thread));
gst_object_unref (GST_OBJECT (thread));
}
g_print ("create/ref/unref/unref %d thread %ld\n", iters, vmsize()-usage1);
thread = gst_thread_new ("somethread");
gst_object_ref (GST_OBJECT (thread));
gst_object_destroy (GST_OBJECT (thread));
gst_object_unref (GST_OBJECT (thread));
gst_object_unref (GST_OBJECT (thread));
g_print ("craete/ref/destroy/unref/unref new thread %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
thread = gst_thread_new ("somethread");
gst_object_ref (GST_OBJECT (thread));
gst_object_destroy (GST_OBJECT (thread));
gst_object_unref (GST_OBJECT (thread));
gst_object_unref (GST_OBJECT (thread));
}
g_print ("craete/ref/destroy/unref/unref %d threads %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
thread = gst_thread_new ("somethread");
gst_object_ref (GST_OBJECT (thread));
gst_element_set_name (thread, "testing123");
gst_object_destroy (GST_OBJECT (thread));
gst_element_set_name (thread, "testing123");
gst_object_unref (GST_OBJECT (thread));
gst_object_unref (GST_OBJECT (thread));
}
g_print ("craete/ref/destroy/unref/unref %d threads with name %ld\n", iters, vmsize()-usage1);
thread = gst_thread_new ("somethread");
for (i=0; i<iters;i++) {
gst_element_set_name (thread, "testing");
}
gst_object_unref (GST_OBJECT (thread));
g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
thread = gst_thread_new ("somethread");
element = gst_element_new ();
gst_element_set_name (element, "test1");
gst_bin_add (GST_BIN (thread), element);
gst_object_unref (GST_OBJECT (thread));
}
g_print ("create/unref %d thread with one element %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
thread = create_thread();
gst_object_unref (GST_OBJECT (thread));
}
g_print ("create/unref %d thread with children %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters/2;i++) {
thread = create_thread_ghostpads();
gst_object_unref (GST_OBJECT (thread));
}
g_print ("create/unref %d thread with children and ghostpads %ld\n", iters/2, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test1();
}
g_print ("add/remove test1 %d in thread %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test2();
}
g_print ("add/remove test2 %d in thread %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test3();
}
g_print ("add/destroy/remove test3 %d in thread %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test4();
}
g_print ("add/destroy/remove test4 %d in thread %ld\n", iters, vmsize()-usage1);
g_print ("leaked: %ld\n", vmsize()-usage1);
return (vmsize()-usage1 ? -1 : 0);
}

35
tests/reaping.c Normal file
View file

@ -0,0 +1,35 @@
#include <stdio.h>
#include <gst/gst.h>
int main(int argc,char *argv[]) {
GstBin *pipeline, *thread;
GstElement *src, *queue1, *sink;
gst_init(&argc,&argv);
gst_info_set_categories(-1);
gst_debug_set_categories(-1);
pipeline = gst_pipeline_new("pipeline");
thread = gst_thread_new("thread");
src = gst_elementfactory_make("fakesrc","src");
queue1 = gst_elementfactory_make("queue","queue");
sink = gst_elementfactory_make("fakesink","sink");
gst_bin_add(pipeline,src);
gst_bin_add(pipeline,queue1);
gst_bin_add(pipeline,GST_ELEMENT(thread));
gst_bin_add(thread,sink);
gst_element_add_ghost_pad(GST_ELEMENT(thread),gst_element_get_pad(sink,"sink"),"sink");
gst_element_connect (src,"src",queue1,"sink");
gst_element_connect (queue1, "src", thread, "sink");
fprintf(stderr,"\n\n\n");
gst_element_set_state (pipeline, GST_STATE_READY);
fprintf(stderr,"\n\n\n");
gst_element_set_state (pipeline, GST_STATE_NULL);
}

View file

@ -2,7 +2,7 @@
gboolean state_change(GstElement *element,GstElementState state) { gboolean state_change(GstElement *element,GstElementState state) {
g_print(">STATES: element '%s' state set to %d(%s)\n", g_print(">STATES: element '%s' state set to %d(%s)\n",
gst_element_get_name(element),state,_gst_print_statename(state)); gst_element_get_name(element),state,gst_element_statename(state));
g_print(">STATES: element state is actually %d\n",GST_STATE(element)); g_print(">STATES: element state is actually %d\n",GST_STATE(element));
return TRUE; return TRUE;
@ -37,15 +37,15 @@ int main(int argc,char *argv[]) {
GTK_SIGNAL_FUNC(state_change),NULL); GTK_SIGNAL_FUNC(state_change),NULL);
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(src), g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(src),
GST_STATE(src),_gst_print_statename(GST_STATE(src))); GST_STATE(src),gst_element_statename(GST_STATE(src)));
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(subbin), g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(subbin),
GST_STATE(subbin),_gst_print_statename(GST_STATE(subbin))); GST_STATE(subbin),gst_element_statename(GST_STATE(subbin)));
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(filter), g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(filter),
GST_STATE(filter),_gst_print_statename(GST_STATE(filter))); GST_STATE(filter),gst_element_statename(GST_STATE(filter)));
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(sink), g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(sink),
GST_STATE(sink),_gst_print_statename(GST_STATE(sink))); GST_STATE(sink),gst_element_statename(GST_STATE(sink)));
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(bin), g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(bin),
GST_STATE(bin),_gst_print_statename(GST_STATE(bin))); GST_STATE(bin),gst_element_statename(GST_STATE(bin)));
gst_bin_add(GST_BIN(subbin),filter); gst_bin_add(GST_BIN(subbin),filter);
gst_element_add_ghost_pad(GST_ELEMENT(bin),gst_element_get_pad(filter,"sink"),"sink"); gst_element_add_ghost_pad(GST_ELEMENT(bin),gst_element_get_pad(filter,"sink"),"sink");

51
tests/threadlock.c Normal file
View file

@ -0,0 +1,51 @@
#include <stdio.h>
#include <gst/gst.h>
int main(int argc,char *argv[]) {
GstBin *pipeline, *thread;
GstElement *src, *queue1, *sink;
gst_init(&argc,&argv);
gst_info_set_categories(-1);
gst_debug_set_categories(-1);
pipeline = gst_pipeline_new("pipeline");
thread = gst_thread_new("thread");
src = gst_elementfactory_make("fakesrc","src");
sink = gst_elementfactory_make("fakesink","sink");
fprintf(stderr,"ADDING src\n");
gst_bin_add(thread,src);
fprintf(stderr,"ADDING sink\n");
gst_bin_add(thread,sink);
fprintf(stderr,"ADDING thread\n");
gst_bin_add(pipeline,GST_ELEMENT(thread));
// gst_element_add_ghost_pad(GST_ELEMENT(thread),gst_element_get_pad(sink,"sink"),"sink");
fprintf(stderr,"CONNECTING src to sink\n");
gst_element_connect (src, "src", sink, "sink");
fprintf(stderr,"\nSWITCHING to READY:\n");
gst_element_set_state (thread, GST_STATE_READY);
fprintf(stderr,"\nPIPELINE sched:\n");
gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
fprintf(stderr,"\nTHREAD sched:\n");
gst_schedule_show(GST_ELEMENT_SCHED(thread));
fprintf(stderr,"\nSWITCHING to PLAYING:\n");
gst_element_set_state (thread, GST_STATE_PLAYING);
gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
gst_schedule_show(GST_ELEMENT_SCHED(thread));
fprintf(stderr,"sleeping...\n");
sleep(1);
fprintf(stderr,"done sleeping...\n");
fprintf(stderr,"\nSWITCHING to READY:\n");
gst_element_set_state (thread, GST_STATE_READY);
gst_schedule_show(GST_ELEMENT_SCHED(pipeline));
gst_schedule_show(GST_ELEMENT_SCHED(thread));
sleep(1);
}

View file

@ -0,0 +1,18 @@
SUBDIRS =
testprogs = object element pad element_pad bin thread
object_SOURCES = object.c mem.c
element_SOURCES = element.c mem.c
pad_SOURCES = pad.c mem.c
element_pad_SOURCES = element_pad.c mem.c
bin_SOURCES = bin.c mem.c
thread_SOURCES = thread.c mem.c
TESTS = $(testprogs)
check_PROGRAMS = $(testprogs)
# we have nothing but apps here, we can do this safely
LIBS += $(GST_LIBS)
CFLAGS += $(GST_CFLAGS)

272
testsuite/refcounting/bin.c Normal file
View file

@ -0,0 +1,272 @@
#include <gst/gst.h>
#define ITERS 100000
#include <stdlib.h>
#include "mem.h"
static GstElement*
create_bin (void)
{
GstElement *bin;
GstElement *element;
bin = gst_bin_new ("testbin");
element = gst_element_new ();
gst_element_set_name (element, "test1");
gst_bin_add (GST_BIN (bin), element);
element = gst_element_new ();
gst_element_set_name (element, "test2");
gst_bin_add (GST_BIN (bin), element);
return bin;
}
static GstElement*
create_bin_ghostpads (void)
{
GstElement *bin;
GstElement *element1, *element2;
bin = gst_bin_new ("testbin");
element1 = gst_element_new ();
gst_element_set_name (element1, "test1");
gst_element_add_pad (element1, gst_pad_new ("src1", GST_PAD_SRC));
gst_bin_add (GST_BIN (bin), element1);
element2 = gst_element_new ();
gst_element_set_name (element2, "test2");
gst_element_add_pad (element2, gst_pad_new ("sink1", GST_PAD_SINK));
gst_bin_add (GST_BIN (bin), element2);
gst_element_connect (element1, "src1", element2, "sink1");
gst_element_add_ghost_pad (bin, gst_element_get_pad (element2, "sink1"), "ghost_sink");
return bin;
}
static void
add_remove_test1 (void)
{
GstElement *bin;
GstElement *element;
bin = gst_bin_new ("testbin");
element = gst_element_new ();
gst_element_set_name (element, "test1");
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
gst_bin_remove (GST_BIN (bin), element);
gst_object_unref (GST_OBJECT (bin));
}
static void
add_remove_test2 (void)
{
GstElement *bin;
GstElement *element;
bin = gst_bin_new ("testbin");
element = gst_element_new ();
gst_element_set_name (element, "test1");
gst_object_ref (GST_OBJECT (element));
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
gst_bin_remove (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
g_assert (!GST_OBJECT_DESTROYED (element));
gst_object_destroy (GST_OBJECT (element));
g_assert (GST_OBJECT_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (bin));
}
static void
add_remove_test3 (void)
{
GstElement *bin;
GstElement *element;
bin = gst_bin_new ("testbin");
element = gst_element_new ();
gst_element_set_name (element, "test1");
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
gst_object_destroy (GST_OBJECT (element));
g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
gst_object_unref (GST_OBJECT (bin));
}
static void
add_remove_test4 (void)
{
GstElement *bin, *bin2;
GstElement *element;
bin = gst_bin_new ("testbin");
element = gst_element_new ();
gst_element_set_name (element, "test1");
g_assert (GST_OBJECT_FLOATING (element));
gst_bin_add (GST_BIN (bin), element);
g_assert (!GST_OBJECT_FLOATING (element));
bin2 = create_bin ();
g_assert (GST_OBJECT_FLOATING (bin2));
gst_bin_add (GST_BIN (bin), bin2);
g_assert (!GST_OBJECT_FLOATING (bin2));
gst_object_destroy (GST_OBJECT (bin2));
g_assert (gst_bin_get_by_name (GST_BIN (bin), "testbin") == NULL);
gst_object_destroy (GST_OBJECT (element));
g_assert (gst_bin_get_by_name (GST_BIN (bin), "test1") == NULL);
gst_object_unref (GST_OBJECT (bin));
}
int
main (int argc, gchar *argv[])
{
GstElement *bin;
long usage1;
gint i, iters;
gst_init (&argc, &argv);
if (argc == 2)
iters = atoi (argv[1]);
else
iters = ITERS;
g_print ("starting test\n");
usage1 = vmsize();
bin = gst_bin_new ("somebin");
gst_object_unref (GST_OBJECT (bin));
g_print ("create/unref new bin %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/unref %d bins %ld\n", iters, vmsize()-usage1);
bin = gst_bin_new ("somebin");
g_assert (GST_OBJECT_FLOATING (bin));
gst_object_ref (GST_OBJECT (bin));
gst_object_sink (GST_OBJECT (bin));
g_assert (!GST_OBJECT_FLOATING (bin));
gst_object_unref (GST_OBJECT (bin));
g_print ("create/ref/sink/unref new bin %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_object_sink (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/ref/sink/unref %d bins %ld\n", iters, vmsize()-usage1);
bin = gst_bin_new ("somebin");
g_assert (!GST_OBJECT_DESTROYED (bin));
gst_object_destroy (GST_OBJECT (bin));
g_assert (GST_OBJECT_DESTROYED (bin));
gst_object_unref (GST_OBJECT (bin));
g_print ("create/destroy/unref new bin %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_destroy (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/destroy/unref %d bin %ld\n", iters, vmsize()-usage1);
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
g_print ("create/ref/unref/unref new bin %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/ref/unref/unref %d bin %ld\n", iters, vmsize()-usage1);
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_object_destroy (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
g_print ("craete/ref/destroy/unref/unref new bin %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_object_destroy (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
}
g_print ("craete/ref/destroy/unref/unref %d bins %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = gst_bin_new ("somebin");
gst_object_ref (GST_OBJECT (bin));
gst_element_set_name (bin, "testing123");
gst_object_destroy (GST_OBJECT (bin));
gst_element_set_name (bin, "testing123");
gst_object_unref (GST_OBJECT (bin));
gst_object_unref (GST_OBJECT (bin));
}
g_print ("craete/ref/destroy/unref/unref %d bins with name %ld\n", iters, vmsize()-usage1);
bin = gst_bin_new ("somebin");
for (i=0; i<iters;i++) {
gst_element_set_name (bin, "testing");
}
gst_object_unref (GST_OBJECT (bin));
g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
bin = create_bin();
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/unref %d bin with children %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters/2;i++) {
bin = create_bin_ghostpads();
gst_object_unref (GST_OBJECT (bin));
}
g_print ("create/unref %d bin with children and ghostpads %ld\n", iters/2, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test1();
}
g_print ("add/remove test1 %d in bin %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test2();
}
g_print ("add/remove test2 %d in bin %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test3();
}
g_print ("add/destroy/remove test3 %d in bin %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
add_remove_test4();
}
g_print ("add/destroy/remove test4 %d in bin %ld\n", iters, vmsize()-usage1);
g_print ("leaked: %ld\n", vmsize()-usage1);
return (vmsize()-usage1 ? -1 : 0);
}

View file

@ -0,0 +1,116 @@
#include <gst/gst.h>
#define ITERS 100000
#include <stdlib.h>
#include "mem.h"
int
main (int argc, gchar *argv[])
{
GstElement *element;
long usage1;
gint i, iters;
gst_init (&argc, &argv);
if (argc == 2)
iters = atoi (argv[1]);
else
iters = ITERS;
g_print ("starting test\n");
usage1 = vmsize();
element = gst_element_new ();
gst_object_unref (GST_OBJECT (element));
g_print ("create/unref new element %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_unref (GST_OBJECT (element));
}
g_print ("create/unref %d elements %ld\n", iters, vmsize()-usage1);
element = gst_element_new ();
g_assert (GST_OBJECT_FLOATING (element));
gst_object_ref (GST_OBJECT (element));
gst_object_sink (GST_OBJECT (element));
g_assert (!GST_OBJECT_FLOATING (element));
gst_object_unref (GST_OBJECT (element));
g_print ("create/ref/sink/unref new element %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_object_sink (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
}
g_print ("create/ref/sink/unref %d elements %ld\n", iters, vmsize()-usage1);
element = gst_element_new ();
g_assert (!GST_OBJECT_DESTROYED (element));
gst_object_destroy (GST_OBJECT (element));
g_assert (GST_OBJECT_DESTROYED (element));
gst_object_unref (GST_OBJECT (element));
g_print ("create/destroy/unref new element %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_destroy (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
}
g_print ("create/destroy/unref %d element %ld\n", iters, vmsize()-usage1);
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
g_print ("create/ref/unref/unref new element %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
}
g_print ("create/ref/unref/unref %d element %ld\n", iters, vmsize()-usage1);
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_object_destroy (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
g_print ("craete/ref/destroy/unref/unref new element %ld\n", vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_object_destroy (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
}
g_print ("craete/ref/destroy/unref/unref %d elements %ld\n", iters, vmsize()-usage1);
for (i=0; i<iters;i++) {
element = gst_element_new ();
gst_object_ref (GST_OBJECT (element));
gst_element_set_name (element, "testing123");
gst_object_destroy (GST_OBJECT (element));
gst_element_set_name (element, "testing123");
gst_object_unref (GST_OBJECT (element));
gst_object_unref (GST_OBJECT (element));
}
g_print ("craete/ref/destroy/unref/unref %d elements with name %ld\n", iters, vmsize()-usage1);
element = gst_element_new ();
for (i=0; i<iters;i++) {
gst_element_set_name (element, "testing");
}
gst_object_unref (GST_OBJECT (element));
g_print ("set name %d times %ld\n", iters, vmsize()-usage1);
g_print ("leaked: %ld\n", vmsize()-usage1);
return (vmsize()-usage1 ? -1 : 0);
}

Some files were not shown because too many files have changed in this diff Show more