mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 03:31:05 +00:00
Merged from INCSCHED on 200505251!!!
Original commit message from CVS: Merged from INCSCHED on 200505251!!!
This commit is contained in:
parent
54271eca8e
commit
4a583683e5
111 changed files with 8357 additions and 1740 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -11,6 +11,8 @@ config.sub
|
|||
configure
|
||||
gstreamer-[0-9]*
|
||||
gstreamer-config
|
||||
gstreamer.pc
|
||||
gstreamer-uninstalled.pc
|
||||
gstreamer.spec
|
||||
libtool
|
||||
ltconfig
|
||||
|
|
2
AUTHORS
2
AUTHORS
|
@ -3,6 +3,8 @@ Matt Howell <mhowell@users.sourceforge.net>
|
|||
Brent Bradburn <bbradburn@users.sourceforge.net>
|
||||
Wim Taymans <wim.taymans@tvd.be>
|
||||
Richard Boulton <richard@tartarus.org>
|
||||
Zaheer Merali <zaheer@grid9.net>
|
||||
- thread synchronization rework
|
||||
David I. Lehn <dlehn@users.sourceforge.net>
|
||||
- debian packaging
|
||||
- various fixes
|
||||
|
|
|
@ -26,9 +26,14 @@ bin_SCRIPTS = gstreamer-config
|
|||
m4datadir = $(datadir)/aclocal
|
||||
m4data_DATA = gstreamer.m4
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = gstreamer.pc
|
||||
|
||||
man_MANS = gstreamer-config.1
|
||||
|
||||
EXTRA_DIST = gstreamer.spec.in gstreamer-config.in gstreamer.m4 LICENSE REQUIREMENTS $(man_MANS)
|
||||
EXTRA_DIST = gstreamer.spec.in gstreamer-config.in gstreamer.m4 \
|
||||
gstreamer.pc.in gstreamer-uninstall.pc.in \
|
||||
LICENSE REQUIREMENTS ABOUT-NLS $(man_MANS)
|
||||
|
||||
dist-hook:
|
||||
cp gstreamer.spec $(distdir)
|
||||
|
|
15
autogen.sh
15
autogen.sh
|
@ -79,24 +79,9 @@ autoheader
|
|||
autoconf
|
||||
automake --add-missing
|
||||
|
||||
if [ "x$1" = "x--autogen-recurse" ];then
|
||||
exit # the rest will happen later
|
||||
fi
|
||||
|
||||
#for dir in `find * -name autogen.sh -print | grep -v '^autogen.sh$' | \
|
||||
# sed 's/autogen.sh$//'`;do
|
||||
# echo "Recursively running autogen.sh in $dir"
|
||||
# pushd $dir > /dev/null
|
||||
# ./autogen.sh --autogen-recurse "$@"
|
||||
# popd > /dev/null
|
||||
#done
|
||||
|
||||
# now remove the cache, because it can be considered dangerous in this case
|
||||
rm -f config.cache
|
||||
|
||||
# For busy application developers (Hadess)
|
||||
# ./configure --enable-maintainer-mode --enable-debug --enable-debug-verbose --disable-docs-build "$@"
|
||||
|
||||
./configure --enable-maintainer-mode --enable-plugin-srcdir --enable-debug --enable-debug-verbose "$@"
|
||||
|
||||
echo
|
||||
|
|
75
configure.in
75
configure.in
|
@ -417,35 +417,75 @@ AC_SUBST(X_LIBS)
|
|||
|
||||
dnl Check for the Xv library
|
||||
xvsave_LIBS=${LIBS}
|
||||
AC_CHECK_LIB(Xv, XvQueryExtension, HAVE_LIBXV=yes, HAVE_LIBXV=no, $X_LIBS $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS)
|
||||
AC_CHECK_LIB(Xv, XvQueryExtension,
|
||||
HAVE_LIBXV=yes
|
||||
AC_DEFINE(HAVE_LIBXV),
|
||||
HAVE_LIBXV=no,
|
||||
$X_LIBS $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS
|
||||
)
|
||||
LIBS=${xvsave_LIBS}
|
||||
AC_CHECK_HEADER(X11/extensions/Xv.h, :, HAVE_LIBXV=no)
|
||||
AC_CHECK_HEADER(X11/extensions/Xvlib.h, :, HAVE_LIBXV=no)
|
||||
|
||||
dnl Check for OSS audio
|
||||
AC_CHECK_HEADER(sys/soundcard.h, HAVE_OSS=yes, HAVE_OSS=no)
|
||||
AC_CHECK_HEADER(sys/soundcard.h,
|
||||
AC_DEFINE(HAVE_OSS)
|
||||
HAVE_OSS=yes, []
|
||||
)
|
||||
|
||||
dnl Check for xaudio
|
||||
AC_CHECK_HEADER(xaudio/decoder.h, HAVE_XAUDIO=yes, HAVE_XAUDIO=no)
|
||||
AC_CHECK_HEADER(xaudio/decoder.h,
|
||||
AC_DEFINE(HAVE_XAUDIO)
|
||||
HAVE_XAUDIO="yes",
|
||||
AC_MSG_WARN(
|
||||
***** NOTE: These plugins won't be built: gstxa
|
||||
)
|
||||
HAVE_XAUDIO="no",
|
||||
)
|
||||
|
||||
dnl Check for libmad
|
||||
AC_MSG_CHECKING(MAD library)
|
||||
AC_CHECK_LIB(mad, mad_decoder_finish, HAVE_LIBMAD=yes, HAVE_LIBMAD=no, )
|
||||
AC_CHECK_HEADER(mad.h, :, HAVE_LIBMAD=no)
|
||||
AC_CHECK_LIB(mad, mad_decoder_finish,
|
||||
HAVE_LIBMAD=yes
|
||||
AC_DEFINE(HAVE_LIBMAD),
|
||||
AC_MSG_WARN(
|
||||
***** NOTE: These plugins won't be built: mad
|
||||
)
|
||||
HAVE_LIBMAD=no,
|
||||
)
|
||||
|
||||
dnl Check for libvorbis
|
||||
AC_MSG_CHECKING(Vorbis library)
|
||||
AC_CHECK_LIB(vorbis, ogg_sync_init, HAVE_VORBIS=yes, HAVE_VORBIS=no, )
|
||||
AC_CHECK_HEADER(vorbis/codec.h, :, HAVE_VORBIS=no)
|
||||
AC_CHECK_LIB(vorbis, ogg_sync_init,
|
||||
HAVE_VORBIS=yes
|
||||
AC_DEFINE(HAVE_VORBIS),
|
||||
AC_MSG_WARN(
|
||||
***** NOTE: These plugins won't be built: vorbisdec vorbisenc
|
||||
)
|
||||
HAVE_VORBIS=no,
|
||||
)
|
||||
|
||||
dnl Check for libjpeg
|
||||
AC_MSG_CHECKING(libjpeg library)
|
||||
AC_CHECK_LIB(jpeg, jpeg_set_defaults, HAVE_LIBJPEG=yes, HAVE_LIBJPEG=no, )
|
||||
AC_CHECK_HEADER(jpeglib.h, :, HAVE_LIBJPEG=no)
|
||||
AC_CHECK_LIB(jpeg, jpeg_set_defaults,
|
||||
HAVE_LIBJPEG=yes
|
||||
AC_DEFINE(HAVE_LIBJPEG),
|
||||
AC_MSG_WARN(
|
||||
***** NOTE: These plugins won't be built: jpegdec jpegenc
|
||||
)
|
||||
HAVE_LIBJPEG=no,
|
||||
)
|
||||
|
||||
dnl Check for libHermes
|
||||
dnl Check for Hermes
|
||||
AC_MSG_CHECKING(Hermes library)
|
||||
AC_CHECK_LIB(Hermes, Hermes_ConverterInstance, HAVE_LIBHERMES=yes, HAVE_LIBHERMES=no, )
|
||||
AC_CHECK_LIB(Hermes, Hermes_ConverterInstance,
|
||||
HAVE_LIBHERMES=yes
|
||||
AC_DEFINE(HAVE_LIBHERMES),
|
||||
AC_MSG_WARN(
|
||||
***** NOTE: These plugins won't be built: colorspace
|
||||
)
|
||||
HAVE_LIBHERMES=no,
|
||||
)
|
||||
AC_CHECK_HEADER(Hermes/Hermes.h, :, HAVE_LIBHERMES=no)
|
||||
|
||||
dnl Check for cdparanoia
|
||||
|
@ -672,13 +712,13 @@ esac],
|
|||
[:]) dnl Default value
|
||||
|
||||
AC_ARG_ENABLE(docs-build,
|
||||
[ --disable-docs-build disable all building of documentation],
|
||||
[ --enable-docs-build enable building of documentation],
|
||||
[case "${enableval}" in
|
||||
yes) BUILD_DOCS=yes ;;
|
||||
no) BUILD_DOCS=no ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-docs-build) ;;
|
||||
esac],
|
||||
[BUILD_DOCS=yes]) dnl Default value
|
||||
[BUILD_DOCS=no]) dnl Default value
|
||||
|
||||
AC_ARG_ENABLE(plugin-docs,
|
||||
[ --enable-plugin-docs enable the building of plugin documentation
|
||||
|
@ -889,7 +929,11 @@ dnl ##############################
|
|||
dnl # Set up the defaults cflags #
|
||||
dnl ##############################
|
||||
dnl CC="kgcc"
|
||||
if test "x$USE_PROFILING" = xyes; then
|
||||
CFLAGS="$CORE_CFLAGS $CFLAGS -Wall"
|
||||
else
|
||||
CFLAGS="$CORE_CFLAGS $CFLAGS -O6 -Wall"
|
||||
fi
|
||||
LIBS="$CORE_LIBS $LIBS"
|
||||
AC_SUBST(CORE_LIBS)
|
||||
AC_SUBST(CORE_CFLAGS)
|
||||
|
@ -1041,6 +1085,7 @@ tests/Makefile
|
|||
tests/sched/Makefile
|
||||
tests/eos/Makefile
|
||||
testsuite/Makefile
|
||||
testsuite/refcounting/Makefile
|
||||
testsuite/capsnego/Makefile
|
||||
tests/nego/Makefile
|
||||
examples/Makefile
|
||||
|
@ -1073,5 +1118,7 @@ docs/fwg/Makefile
|
|||
debian/Makefile
|
||||
stamp.h
|
||||
gstreamer-config
|
||||
gstreamer.spec])
|
||||
gstreamer.spec
|
||||
gstreamer.pc
|
||||
gstreamer-uninstalled.pc])
|
||||
AC_OUTPUT_COMMANDS([chmod +x gstreamer-config])
|
||||
|
|
|
@ -61,9 +61,9 @@ The maximum number of cothreads we are going to support.
|
|||
@argv:
|
||||
@flags:
|
||||
@sp:
|
||||
@jmp:
|
||||
@top_sp:
|
||||
@pc:
|
||||
@jmp:
|
||||
|
||||
<!-- ##### STRUCT cothread_context ##### -->
|
||||
<para>
|
||||
|
|
|
@ -267,24 +267,6 @@ circumstances.
|
|||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_element_set_manager ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@element:
|
||||
@manager:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_element_get_manager ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@element:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gst_element_set_parent ##### -->
|
||||
<para>
|
||||
|
||||
|
|
|
@ -46,3 +46,8 @@ The <classname>GstFakeSrc</classname> generates empty buffers. (fakesrc)
|
|||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GstFakeSrc:eos ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
|
|
|
@ -24,8 +24,10 @@ Thread flags:
|
|||
</para>
|
||||
|
||||
@GST_THREAD_CREATE: The thread is being created.
|
||||
@GST_THREAD_STATE_STARTED:
|
||||
@GST_THREAD_STATE_SPINNING: The thread is runnning
|
||||
@GST_THREAD_STATE_REAPING: The thread is ending.
|
||||
@GST_THREAD_STATE_ELEMENT_CHANGED:
|
||||
@GST_THREAD_FLAG_LAST: subclass use this to start their enumeration
|
||||
|
||||
<!-- ##### STRUCT GstThread ##### -->
|
||||
|
|
125
docs/random/matth/scheduling.txt
Normal file
125
docs/random/matth/scheduling.txt
Normal 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)
|
|
@ -8,4 +8,4 @@ endif
|
|||
SUBDIRS = $(GNOME_SUBDS) \
|
||||
helloworld helloworld2 \
|
||||
queue queue2 queue3 queue4 \
|
||||
launch thread xml plugins typefind
|
||||
launch thread xml plugins typefind mixer
|
||||
|
|
|
@ -2,93 +2,35 @@
|
|||
#include <gnome.h>
|
||||
|
||||
static void
|
||||
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
|
||||
autoplug_have_size (GstElement *element, guint width, guint height,
|
||||
GtkWidget *socket)
|
||||
{
|
||||
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
|
||||
|
||||
*(gboolean *)data = TRUE;
|
||||
gtk_widget_set_usize(socket,width,height);
|
||||
}
|
||||
|
||||
gboolean
|
||||
idle_func (gpointer data)
|
||||
static void
|
||||
gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
||||
{
|
||||
return gst_bin_iterate (GST_BIN (data));
|
||||
}
|
||||
|
||||
static GstCaps*
|
||||
gst_play_typefind (GstBin *bin, GstElement *element)
|
||||
{
|
||||
gboolean found = FALSE;
|
||||
GstElement *typefind;
|
||||
GstCaps *caps = NULL;
|
||||
|
||||
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
|
||||
GST_ELEMENT_NAME(element), &found);
|
||||
|
||||
typefind = gst_elementfactory_make ("typefind", "typefind");
|
||||
g_return_val_if_fail (typefind != NULL, FALSE);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
|
||||
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
|
||||
|
||||
gst_pad_connect (gst_element_get_pad (element, "src"),
|
||||
gst_element_get_pad (typefind, "sink"));
|
||||
|
||||
gst_bin_add (bin, typefind);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
|
||||
|
||||
// push a buffer... the have_type signal handler will set the found flag
|
||||
gst_bin_iterate (bin);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
|
||||
|
||||
caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
|
||||
|
||||
gst_pad_disconnect (gst_element_get_pad (element, "src"),
|
||||
gst_element_get_pad (typefind, "sink"));
|
||||
gst_bin_remove (bin, typefind);
|
||||
gst_object_unref (GST_OBJECT (typefind));
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
GstElement *disksrc, *osssink, *videosink;
|
||||
GstElement *bin;
|
||||
GstElement *osssink, *videosink;
|
||||
GtkWidget *appwindow;
|
||||
GstCaps *srccaps;
|
||||
GstElement *new_element;
|
||||
GstAutoplug *autoplug;
|
||||
GtkWidget *socket;
|
||||
GstElement *autobin;
|
||||
GstElement *disksrc;
|
||||
GstElement *cache;
|
||||
|
||||
g_thread_init(NULL);
|
||||
gst_init(&argc,&argv);
|
||||
gnome_init("autoplug","0.0.1", argc,argv);
|
||||
GST_DEBUG (0,"GstPipeline: play have type\n");
|
||||
|
||||
if (argc != 2) {
|
||||
g_print("usage: %s <filename>\n", argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
|
||||
/* create a new bin to hold the elements */
|
||||
bin = gst_pipeline_new("pipeline");
|
||||
g_assert(bin != NULL);
|
||||
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");
|
||||
|
||||
/* 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 (bin), disksrc);
|
||||
|
||||
srccaps = gst_play_typefind (GST_BIN (bin), disksrc);
|
||||
|
||||
if (!srccaps) {
|
||||
g_print ("could not autoplug, unknown media type...\n");
|
||||
exit (-1);
|
||||
}
|
||||
// disconnect the typefind from the pipeline and remove it
|
||||
gst_element_disconnect (cache, "src", typefind, "sink");
|
||||
gst_bin_remove (GST_BIN (autobin), typefind);
|
||||
|
||||
/* and an audio sink */
|
||||
osssink = gst_elementfactory_make("osssink", "play_audio");
|
||||
|
@ -102,7 +44,7 @@ int main(int argc,char *argv[])
|
|||
g_assert (autoplug != NULL);
|
||||
|
||||
new_element = gst_autoplug_to_renderers (autoplug,
|
||||
srccaps,
|
||||
caps,
|
||||
videosink,
|
||||
osssink,
|
||||
NULL);
|
||||
|
@ -112,14 +54,13 @@ int main(int argc,char *argv[])
|
|||
exit (-1);
|
||||
}
|
||||
|
||||
gst_bin_remove (GST_BIN (bin), disksrc);
|
||||
// FIXME hack, reparent the disksrc so the scheduler doesn't break
|
||||
bin = gst_pipeline_new("pipeline");
|
||||
gst_element_set_name (new_element, "new_element");
|
||||
|
||||
gst_bin_add (GST_BIN (bin), disksrc);
|
||||
gst_bin_add (GST_BIN (bin), new_element);
|
||||
gst_bin_add (GST_BIN (autobin), new_element);
|
||||
|
||||
gst_element_connect (disksrc, "src", new_element, "sink");
|
||||
gtk_object_set (GTK_OBJECT (cache), "reset", TRUE, NULL);
|
||||
|
||||
gst_element_connect (cache, "src", new_element, "sink");
|
||||
|
||||
appwindow = gnome_app_new ("autoplug demo","autoplug demo");
|
||||
|
||||
|
@ -132,22 +73,103 @@ int main(int argc,char *argv[])
|
|||
gtk_widget_realize (socket);
|
||||
gtk_socket_steal (GTK_SOCKET (socket),
|
||||
gst_util_get_int_arg (GTK_OBJECT (videosink), "xid"));
|
||||
gtk_widget_set_usize(socket,320,240);
|
||||
|
||||
gtk_widget_show_all (appwindow);
|
||||
|
||||
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 */
|
||||
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_PLAYING);
|
||||
|
||||
gtk_idle_add(idle_func, bin);
|
||||
gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
|
||||
gtk_idle_add (idle_func, pipeline);
|
||||
gst_main ();
|
||||
|
||||
/* stop the bin */
|
||||
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_NULL);
|
||||
/* stop the pipeline */
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
|
||||
|
||||
gst_pipeline_destroy(bin);
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
* demonstrates the adder plugin and the volume envelope plugin
|
||||
* work in progress but do try it out
|
||||
*
|
||||
* Latest change : 16/04/2001
|
||||
* multiple input channels allowed
|
||||
* volume envelope adapted
|
||||
* Version : 0.3
|
||||
* Latest change : 28/04/2001
|
||||
* trying to adapt to incsched
|
||||
* delayed start for channels > 1
|
||||
* now works by quickhacking the
|
||||
* adder plugin to set
|
||||
* GST_ELEMENT_COTHREAD_STOPPING
|
||||
* Version : 0.5
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -15,8 +18,10 @@
|
|||
#include "mixer.h"
|
||||
#include <unistd.h>
|
||||
|
||||
//#define WITH_BUG
|
||||
//#define WITH_BUG2
|
||||
//#define DEBUG
|
||||
|
||||
//#define AUTOPLUG /* define if you want autoplugging of input channels */
|
||||
/* function prototypes */
|
||||
|
||||
input_channel_t* create_input_channel (int id, char* location);
|
||||
|
@ -35,55 +40,50 @@ void eos(GstElement *element)
|
|||
// playing = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
|
||||
{
|
||||
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
|
||||
|
||||
*(gboolean *)data = TRUE;
|
||||
}
|
||||
|
||||
static GstCaps*
|
||||
gst_play_typefind (GstBin *bin, GstElement *element)
|
||||
{
|
||||
gboolean found = FALSE;
|
||||
GstElement *typefind;
|
||||
GstElement *pipeline;
|
||||
GstCaps *caps = NULL;
|
||||
|
||||
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
|
||||
GST_ELEMENT_NAME(element), &found);
|
||||
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\"\n",
|
||||
GST_ELEMENT_NAME(element));
|
||||
|
||||
pipeline = gst_pipeline_new ("autoplug_pipeline");
|
||||
|
||||
typefind = gst_elementfactory_make ("typefind", "typefind");
|
||||
g_return_val_if_fail (typefind != NULL, FALSE);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
|
||||
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
|
||||
|
||||
gst_pad_connect (gst_element_get_pad (element, "src"),
|
||||
gst_element_get_pad (typefind, "sink"));
|
||||
gst_bin_add (bin, typefind);
|
||||
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (bin));
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
// push a buffer... the have_type signal handler will set the found flag
|
||||
gst_bin_iterate (bin);
|
||||
gst_bin_iterate (GST_BIN (pipeline));
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
|
||||
|
||||
gst_pad_disconnect (gst_element_get_pad (element, "src"),
|
||||
gst_element_get_pad (typefind, "sink"));
|
||||
gst_bin_remove (bin, typefind);
|
||||
gst_bin_remove (GST_BIN (pipeline), GST_ELEMENT (bin));
|
||||
gst_object_unref (GST_OBJECT (typefind));
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
int num_channels;
|
||||
gboolean done;
|
||||
|
||||
char buffer[20];
|
||||
|
||||
|
@ -114,11 +114,12 @@ int main(int argc,char *argv[])
|
|||
audiosink = gst_elementfactory_make ("esdsink", "play_audio");
|
||||
|
||||
/* create main bin */
|
||||
main_bin = gst_bin_new("bin");
|
||||
main_bin = gst_pipeline_new("bin");
|
||||
|
||||
/* connect adder and output to bin */
|
||||
|
||||
GST_INFO (0, "main: adding adder to bin");
|
||||
gst_bin_add (GST_BIN(main_bin), adder);
|
||||
GST_INFO (0, "main: adding audiosink to bin");
|
||||
gst_bin_add (GST_BIN(main_bin), audiosink);
|
||||
|
||||
/* connect adder and audiosink */
|
||||
|
@ -126,8 +127,7 @@ int main(int argc,char *argv[])
|
|||
gst_pad_connect(gst_element_get_pad(adder,"src"),
|
||||
gst_element_get_pad(audiosink,"sink"));
|
||||
|
||||
/* create input channels, add to bin and connect */
|
||||
|
||||
/* start looping */
|
||||
input_channels = NULL;
|
||||
|
||||
for (i = 1; i < argc; ++i)
|
||||
|
@ -135,11 +135,14 @@ int main(int argc,char *argv[])
|
|||
printf ("Opening channel %d from file %s...\n", i, argv[i]);
|
||||
channel_in = create_input_channel (i, argv[i]);
|
||||
input_channels = g_list_append (input_channels, channel_in);
|
||||
|
||||
if (i > 1) gst_element_set_state (main_bin, GST_STATE_PAUSED);
|
||||
gst_bin_add (GST_BIN(main_bin), channel_in->pipe);
|
||||
|
||||
/* request pads and connect to adder */
|
||||
GST_INFO (0, "requesting pad\n");
|
||||
pad = gst_element_request_pad_by_name (adder, "sink%d");
|
||||
g_print ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
|
||||
printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
|
||||
sprintf (buffer, "channel%d", i);
|
||||
gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad);
|
||||
|
||||
|
@ -178,24 +181,32 @@ int main(int argc,char *argv[])
|
|||
env_register_cp (channel_in->volenv, num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */
|
||||
}
|
||||
env_register_cp (channel_in->volenv, num_channels * 10.0 , 1.0 / num_channels); /* to end level */
|
||||
}
|
||||
|
||||
/* sleep a few seconds doesn't seem to help anyway */
|
||||
|
||||
printf ("Sleeping a few seconds ...\n");
|
||||
sleep (2);
|
||||
printf ("Waking up ...\n");
|
||||
|
||||
xmlSaveFile("mixer.xml", gst_xml_write(GST_ELEMENT(main_bin)));
|
||||
|
||||
/* start playing */
|
||||
gst_element_set_state(main_bin, GST_STATE_PLAYING);
|
||||
|
||||
// write out the schedule
|
||||
gst_schedule_show(GST_ELEMENT_SCHED(main_bin));
|
||||
playing = TRUE;
|
||||
|
||||
while (playing) {
|
||||
j = 0;
|
||||
//printf ("main: start iterating from 0");
|
||||
while (playing && j < 100)
|
||||
{
|
||||
// printf ("main: iterating %d\n", j);
|
||||
gst_bin_iterate(GST_BIN(main_bin));
|
||||
//fprintf(stderr,"after iterate()\n");
|
||||
++j;
|
||||
}
|
||||
}
|
||||
printf ("main: all the channels are open\n");
|
||||
while (playing)
|
||||
{
|
||||
gst_bin_iterate(GST_BIN(main_bin));
|
||||
//fprintf(stderr,"after iterate()\n");
|
||||
}
|
||||
|
||||
/* stop the bin */
|
||||
gst_element_set_state(main_bin, GST_STATE_NULL);
|
||||
|
||||
|
@ -228,11 +239,10 @@ create_input_channel (int id, char* location)
|
|||
GstAutoplug *autoplug;
|
||||
GstCaps *srccaps;
|
||||
GstElement *new_element;
|
||||
GstElement *decoder;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("DEBUG : c_i_p : creating channel with id %d for file %s\n",
|
||||
GST_DEBUG (0, "c_i_p : creating channel with id %d for file %s\n",
|
||||
id, location);
|
||||
#endif
|
||||
|
||||
/* allocate channel */
|
||||
|
||||
|
@ -245,23 +255,21 @@ create_input_channel (int id, char* location)
|
|||
|
||||
/* create channel */
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("DEBUG : c_i_p : creating pipeline\n");
|
||||
#endif
|
||||
GST_DEBUG (0, "c_i_p : creating pipeline\n");
|
||||
|
||||
channel->pipe = gst_bin_new ("pipeline");
|
||||
sprintf (buffer, "pipeline%d", id);
|
||||
channel->pipe = gst_bin_new (buffer);
|
||||
g_assert(channel->pipe != NULL);
|
||||
|
||||
/* create elements */
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("DEBUG : c_i_p : creating disksrc\n");
|
||||
#endif
|
||||
GST_DEBUG(0, "c_i_p : creating disksrc\n");
|
||||
|
||||
sprintf (buffer, "disksrc%d", id);
|
||||
channel->disksrc = gst_elementfactory_make ("disksrc", buffer);
|
||||
g_assert(channel->disksrc != NULL);
|
||||
|
||||
GST_DEBUG(0, "c_i_p : setting location\n");
|
||||
gtk_object_set(GTK_OBJECT(channel->disksrc),"location", location, NULL);
|
||||
|
||||
/* add disksrc to the bin before autoplug */
|
||||
|
@ -286,8 +294,24 @@ create_input_channel (int id, char* location)
|
|||
printf ("DEBUG : c_i_p : getting srccaps\n");
|
||||
#endif
|
||||
|
||||
#ifdef WITH_BUG
|
||||
srccaps = gst_play_typefind (GST_BIN (channel->pipe), channel->disksrc);
|
||||
#endif
|
||||
#ifdef WITH_BUG2
|
||||
{
|
||||
GstElement *pipeline;
|
||||
|
||||
pipeline = gst_pipeline_new ("autoplug_pipeline");
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), channel->pipe);
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
gst_bin_remove (GST_BIN (pipeline), channel->pipe);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AUTOPLUG
|
||||
if (!srccaps) {
|
||||
g_print ("could not autoplug, unknown media type...\n");
|
||||
exit (-1);
|
||||
|
@ -312,6 +336,23 @@ create_input_channel (int id, char* location)
|
|||
exit (-1);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
new_element = gst_bin_new ("autoplug_bin");
|
||||
|
||||
/* static plug, use mad plugin and assume mp3 input */
|
||||
decoder = gst_elementfactory_make ("mad", "mpg123");
|
||||
|
||||
gst_bin_add (GST_BIN (new_element), decoder);
|
||||
|
||||
gst_element_add_ghost_pad (new_element,
|
||||
gst_element_get_pad (decoder, "sink"), "sink");
|
||||
gst_element_add_ghost_pad (new_element,
|
||||
gst_element_get_pad (decoder, "src"), "src_00");
|
||||
|
||||
#endif
|
||||
xmlSaveFile ("mixer.gst", gst_xml_write (new_element));
|
||||
|
||||
gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
|
||||
gst_bin_add (GST_BIN (channel->pipe), new_element);
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ libgstincludedir = $(includedir)/gst
|
|||
libgstinclude_HEADERS = \
|
||||
cothreads.h \
|
||||
gst.h \
|
||||
gsttypes.h \
|
||||
gstautoplug.h \
|
||||
gstbin.h \
|
||||
gstbuffer.h \
|
||||
|
@ -128,7 +129,7 @@ noinst_HEADERS = \
|
|||
gstsparc.h \
|
||||
gstpropsprivate.h
|
||||
|
||||
CFLAGS = $(LIBGST_CFLAGS)
|
||||
CFLAGS = $(LIBGST_CFLAGS) -D_GNU_SOURCE
|
||||
LIBS = $(LIBGST_LIBS)
|
||||
libgst_la_LDFLAGS = -version-info $(GST_LIBVERSION)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
filterdir = $(libdir)/gst
|
||||
|
||||
filter_LTLIBRARIES = libgststaticautoplug.la libgststaticautoplugrender.la
|
||||
filter_LTLIBRARIES = libgststaticautoplug.la libgststaticautoplugrender.la \
|
||||
libgstautoplugcache.la libgstautoplugger.la
|
||||
|
||||
libgststaticautoplug_la_SOURCES = \
|
||||
gststaticautoplug.c
|
||||
|
@ -8,5 +9,12 @@ libgststaticautoplug_la_SOURCES = \
|
|||
libgststaticautoplugrender_la_SOURCES = \
|
||||
gststaticautoplugrender.c
|
||||
|
||||
libgstautoplugcache_la_SOURCES = gstautoplugcache.c
|
||||
libgstautoplugger_la_SOURCES = gstautoplugger.c
|
||||
|
||||
libgststaticautoplug_la_LDFLAGS = -version-info $(GST_LIBVERSION)
|
||||
libgststaticautoplugrender_la_LDFLAGS = -version-info $(GST_LIBVERSION)
|
||||
libgstautoplugcache_la_LDFLAGS = -version-info $(GST_LIBVERSION)
|
||||
|
||||
noinst_PROGRAMS = autoplugtest
|
||||
autoplugtest_LDADD = $(GST_LIBS)
|
||||
|
|
92
gst/autoplug/autoplugtest.c
Normal file
92
gst/autoplug/autoplugtest.c
Normal 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));
|
||||
}
|
371
gst/autoplug/gstautoplugcache.c
Normal file
371
gst/autoplug/gstautoplugcache.c
Normal 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
|
||||
};
|
||||
|
606
gst/autoplug/gstautoplugger.c
Normal file
606
gst/autoplug/gstautoplugger.c
Normal 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
|
||||
};
|
||||
|
|
@ -124,7 +124,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
|
|||
if (gst_caps_check_compatibility (gst_padtemplate_get_caps (srctemp),
|
||||
gst_padtemplate_get_caps (desttemp))) {
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
|
||||
"factory \"%s\" can connect with factory \"%s\"", src->name, dest->name);
|
||||
"factory \"%s\" can connect with factory \"%s\"\n", src->name, dest->name);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
|
|||
srctemps = g_list_next (srctemps);
|
||||
}
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
|
||||
"factory \"%s\" cannot connect with factory \"%s\"", src->name, dest->name);
|
||||
"factory \"%s\" cannot connect with factory \"%s\"\n", src->name, dest->name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
|
|||
desttemp->direction == GST_PAD_SINK) {
|
||||
if (gst_caps_check_compatibility (GST_PADTEMPLATE_CAPS (srctemp), GST_PADTEMPLATE_CAPS (desttemp))) {
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
|
||||
"factory \"%s\" can connect with factory \"%s\"", src->name, dest->name);
|
||||
"factory \"%s\" can connect with factory \"%s\"\n", src->name, dest->name);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ gst_autoplug_can_match (GstElementFactory *src, GstElementFactory *dest)
|
|||
srctemps = g_list_next (srctemps);
|
||||
}
|
||||
GST_DEBUG (GST_CAT_AUTOPLUG_ATTEMPT,
|
||||
"factory \"%s\" cannot connect with factory \"%s\"", src->name, dest->name);
|
||||
"factory \"%s\" cannot connect with factory \"%s\"\n", src->name, dest->name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -154,12 +154,21 @@ gst_autoplug_pads_autoplug_func (GstElement *src, GstPad *pad, GstElement *sink)
|
|||
if (gst_pad_get_direction(sinkpad) == GST_PAD_SINK &&
|
||||
!GST_PAD_CONNECTED (pad) && !GST_PAD_CONNECTED(sinkpad))
|
||||
{
|
||||
GstElementState state = GST_STATE (gst_element_get_parent (src));
|
||||
|
||||
if (state == GST_STATE_PLAYING)
|
||||
gst_element_set_state (GST_ELEMENT (gst_element_get_parent (src)), GST_STATE_PAUSED);
|
||||
|
||||
if ((connected = gst_pad_connect (pad, sinkpad))) {
|
||||
if (state == GST_STATE_PLAYING)
|
||||
gst_element_set_state (GST_ELEMENT (gst_element_get_parent (src)), GST_STATE_PLAYING);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
GST_DEBUG (0,"pads incompatible %s, %s\n", GST_PAD_NAME (pad), GST_PAD_NAME (sinkpad));
|
||||
}
|
||||
if (state == GST_STATE_PLAYING)
|
||||
gst_element_set_state (GST_ELEMENT (gst_element_get_parent (src)), GST_STATE_PLAYING);
|
||||
}
|
||||
sinkpads = g_list_next(sinkpads);
|
||||
}
|
||||
|
@ -423,12 +432,13 @@ differ:
|
|||
// create a new queue and add to the previous bin
|
||||
queue = gst_elementfactory_make("queue", g_strconcat("queue_", GST_ELEMENT_NAME(element), NULL));
|
||||
GST_DEBUG (0,"adding element \"%s\"\n", GST_ELEMENT_NAME (element));
|
||||
gst_bin_add(GST_BIN(thebin), queue);
|
||||
gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (queue));
|
||||
|
||||
// this will be the new bin for all following elements
|
||||
thebin = gst_elementfactory_make("thread", g_strconcat("thread_", GST_ELEMENT_NAME(element), NULL));
|
||||
|
||||
gst_bin_add(GST_BIN(thebin), queue);
|
||||
gst_autoplug_signal_new_object (GST_AUTOPLUG (autoplug), GST_OBJECT (queue));
|
||||
|
||||
srcpad = gst_element_get_pad(queue, "src");
|
||||
|
||||
gst_autoplug_pads_autoplug(thesrcelement, queue);
|
||||
|
|
|
@ -67,6 +67,11 @@ cothread_init (void)
|
|||
{
|
||||
cothread_context *ctx = (cothread_context *)malloc(sizeof(cothread_context));
|
||||
|
||||
// we consider the initiating process to be cothread 0
|
||||
ctx->nthreads = 1;
|
||||
ctx->current = 0;
|
||||
ctx->data = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
|
||||
GST_INFO (GST_CAT_COTHREADS,"initializing cothreads");
|
||||
|
||||
if (_cothread_key == -1) {
|
||||
|
@ -89,12 +94,14 @@ cothread_init (void)
|
|||
ctx->threads[0]->sp = (void *)CURRENT_STACK_FRAME;
|
||||
ctx->threads[0]->pc = 0;
|
||||
|
||||
GST_INFO (GST_CAT_COTHREADS,"0th thread is %p at sp:%p",ctx->threads[0], ctx->threads[0]->sp);
|
||||
// initialize the lock
|
||||
#ifdef COTHREAD_ATOMIC
|
||||
atomic_set (&ctx->threads[0]->lock, 0);
|
||||
#else
|
||||
ctx->threads[0]->lock = g_mutex_new();
|
||||
#endif
|
||||
|
||||
// we consider the initiating process to be cothread 0
|
||||
ctx->nthreads = 1;
|
||||
ctx->current = 0;
|
||||
ctx->data = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
GST_INFO (GST_CAT_COTHREADS,"0th thread is %p at sp:%p",ctx->threads[0], ctx->threads[0]->sp);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
@ -118,7 +125,7 @@ cothread_create (cothread_context *ctx)
|
|||
}
|
||||
GST_DEBUG (0,"pthread_self() %ld\n",pthread_self());
|
||||
//if (0) {
|
||||
if (pthread_self() == 0) {
|
||||
if (pthread_self() == 0) { // FIXME uh, what does this test really do?
|
||||
s = (cothread_state *)malloc(COTHREAD_STACKSIZE);
|
||||
GST_DEBUG (0,"new stack (case 1) at %p\n",s);
|
||||
} else {
|
||||
|
@ -145,6 +152,13 @@ cothread_create (cothread_context *ctx)
|
|||
// is this needed anymore?
|
||||
s->top_sp = s->sp;
|
||||
|
||||
// initialize the lock
|
||||
#ifdef COTHREAD_ATOMIC
|
||||
atomic_set (s->lock, 0);
|
||||
#else
|
||||
s->lock = g_mutex_new();
|
||||
#endif
|
||||
|
||||
GST_INFO (GST_CAT_COTHREADS,"created cothread #%d: %p at sp:%p", ctx->nthreads, s, s->sp);
|
||||
|
||||
ctx->threads[ctx->nthreads++] = s;
|
||||
|
@ -186,6 +200,18 @@ cothread_main(cothread_context *ctx)
|
|||
return ctx->threads[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* cothread_current)main:
|
||||
*
|
||||
* Returns: the #cothread_state of the main (0th) thread in the current pthread
|
||||
*/
|
||||
cothread_state*
|
||||
cothread_current_main(void)
|
||||
{
|
||||
cothread_context *ctx = pthread_getspecific(_cothread_key);
|
||||
return ctx->threads[0];
|
||||
}
|
||||
|
||||
static void
|
||||
cothread_stub (void)
|
||||
{
|
||||
|
@ -195,6 +221,11 @@ cothread_stub (void)
|
|||
GST_DEBUG_ENTER("");
|
||||
|
||||
thread->flags |= COTHREAD_STARTED;
|
||||
//#ifdef COTHREAD_ATOMIC
|
||||
// // do something here to lock
|
||||
//#else
|
||||
// g_mutex_lock(thread->lock);
|
||||
//#endif
|
||||
while (1) {
|
||||
thread->func(thread->argc,thread->argv);
|
||||
// we do this to avoid ever returning, we just switch to 0th thread
|
||||
|
@ -281,8 +312,22 @@ cothread_switch (cothread_state *thread)
|
|||
#endif
|
||||
if (current == thread) goto selfswitch;
|
||||
|
||||
// unlock the current thread, we're out of that context now
|
||||
#ifdef COTHREAD_ATOMIC
|
||||
// do something to unlock the cothread
|
||||
#else
|
||||
g_mutex_unlock(current->lock);
|
||||
#endif
|
||||
|
||||
// lock the next cothread before we even switch to it
|
||||
#ifdef COTHREAD_ATOMIC
|
||||
// do something to lock the cothread
|
||||
#else
|
||||
g_mutex_lock(thread->lock);
|
||||
#endif
|
||||
|
||||
// find the number of the thread to switch to
|
||||
GST_INFO (GST_CAT_COTHREAD_SWITCH,"switching from cothread %d to to cothread #%d",
|
||||
GST_INFO (GST_CAT_COTHREAD_SWITCH,"switching from cothread #%d to cothread #%d",
|
||||
ctx->current,thread->threadnum);
|
||||
ctx->current = thread->threadnum;
|
||||
|
||||
|
@ -319,7 +364,7 @@ cothread_switch (cothread_state *thread)
|
|||
|
||||
#ifdef COTHREAD_PARANOID
|
||||
nothread:
|
||||
g_print("cothread: there's no thread, strange...\n");
|
||||
g_print("cothread: can't switch to NULL cothread!\n");
|
||||
return;
|
||||
nocontext:
|
||||
g_print("cothread: there's no context, help!\n");
|
||||
|
@ -332,3 +377,35 @@ selfswitch:
|
|||
g_print("cothread: trying to switch to same thread, legal but not necessary\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cothread_lock (cothread_state *thread)
|
||||
{
|
||||
#ifdef COTHREAD_ATOMIC
|
||||
// do something to lock the cothread
|
||||
#else
|
||||
g_mutex_lock(thread->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
cothread_trylock (cothread_state *thread)
|
||||
{
|
||||
#ifdef COTHREAD_ATOMIC
|
||||
// do something to try to lock the cothread
|
||||
#else
|
||||
return g_mutex_trylock(thread->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
cothread_unlock (cothread_state *thread)
|
||||
{
|
||||
#ifdef COTHREAD_ATOMIC
|
||||
// do something to unlock the cothread
|
||||
#else
|
||||
g_mutex_unlock(thread->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
#include <glib.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#ifdef HAVE_ATOMIC_H
|
||||
#include <asm/atomic.h>
|
||||
#endif
|
||||
|
||||
#undef COTHREAD_ATOMIC
|
||||
|
||||
#ifndef CURRENT_STACK_FRAME
|
||||
#define CURRENT_STACK_FRAME ({ char __csf; &__csf; })
|
||||
#endif /* CURRENT_STACK_FRAME */
|
||||
|
@ -47,10 +53,16 @@ struct _cothread_state {
|
|||
|
||||
int flags;
|
||||
void *sp;
|
||||
jmp_buf jmp;
|
||||
/* is this needed any more? */
|
||||
void *top_sp;
|
||||
void *pc;
|
||||
jmp_buf jmp;
|
||||
|
||||
#ifdef COTHREAD_ATOMIC
|
||||
atomic_t lock;
|
||||
#else
|
||||
GMutex *lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -63,6 +75,11 @@ void cothread_switch (cothread_state *thread);
|
|||
void cothread_set_data (cothread_state *thread, gchar *key, gpointer data);
|
||||
gpointer cothread_get_data (cothread_state *thread, gchar *key);
|
||||
|
||||
void cothread_lock (cothread_state *thread);
|
||||
gboolean cothread_trylock (cothread_state *thread);
|
||||
void cothread_unlock (cothread_state *thread);
|
||||
|
||||
cothread_state* cothread_main (cothread_context *ctx);
|
||||
cothread_state* cothread_current_main (void);
|
||||
|
||||
#endif /* __COTHREAD_H__ */
|
||||
|
|
|
@ -49,6 +49,7 @@ enum {
|
|||
ARG_OUTPUT,
|
||||
ARG_PATTERN,
|
||||
ARG_NUM_BUFFERS,
|
||||
ARG_EOS,
|
||||
ARG_SILENT
|
||||
};
|
||||
|
||||
|
@ -125,6 +126,8 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
|
|||
GTK_ARG_READWRITE, ARG_PATTERN);
|
||||
gtk_object_add_arg_type ("GstFakeSrc::num_buffers", GTK_TYPE_INT,
|
||||
GTK_ARG_READWRITE, ARG_NUM_BUFFERS);
|
||||
gtk_object_add_arg_type ("GstFakeSrc::eos", GTK_TYPE_BOOL,
|
||||
GTK_ARG_READWRITE, ARG_EOS);
|
||||
gtk_object_add_arg_type ("GstFakeSrc::silent", GTK_TYPE_BOOL,
|
||||
GTK_ARG_READWRITE, ARG_SILENT);
|
||||
|
||||
|
@ -222,6 +225,10 @@ gst_fakesrc_set_arg (GtkObject *object, GtkArg *arg, guint id)
|
|||
case ARG_NUM_BUFFERS:
|
||||
src->num_buffers = GTK_VALUE_INT (*arg);
|
||||
break;
|
||||
case ARG_EOS:
|
||||
src->eos = GTK_VALUE_BOOL (*arg);
|
||||
GST_INFO (0, "will EOS on next buffer");
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
src->silent = GTK_VALUE_BOOL (*arg);
|
||||
break;
|
||||
|
@ -256,6 +263,8 @@ gst_fakesrc_get_arg (GtkObject *object, GtkArg *arg, guint id)
|
|||
case ARG_NUM_BUFFERS:
|
||||
GTK_VALUE_INT (*arg) = src->num_buffers;
|
||||
break;
|
||||
case ARG_EOS:
|
||||
GTK_VALUE_BOOL (*arg) = src->eos;
|
||||
case ARG_SILENT:
|
||||
GTK_VALUE_BOOL (*arg) = src->silent;
|
||||
break;
|
||||
|
@ -295,6 +304,12 @@ gst_fakesrc_get(GstPad *pad)
|
|||
src->num_buffers--;
|
||||
}
|
||||
|
||||
if (src->eos) {
|
||||
GST_INFO (0, "fakesrc is setting eos on pad");
|
||||
gst_pad_set_eos (pad);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!src->silent)
|
||||
g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad));
|
||||
buf = gst_buffer_new();
|
||||
|
@ -339,6 +354,12 @@ gst_fakesrc_loop(GstElement *element)
|
|||
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();
|
||||
if (!src->silent)
|
||||
g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad));
|
||||
|
|
|
@ -65,6 +65,7 @@ struct _GstFakeSrc {
|
|||
GstElement element;
|
||||
|
||||
gboolean loop_based;
|
||||
gboolean eos;
|
||||
gint numsrcpads;
|
||||
GSList *srcpads;
|
||||
GstFakeSrcOutputType output;
|
||||
|
|
24
gst/gst.c
24
gst/gst.c
|
@ -174,21 +174,6 @@ gst_init_check (int *argc,
|
|||
|
||||
(*argv)[i] = NULL;
|
||||
}
|
||||
else if (!strncmp ("--gst-mask=", (*argv)[i], 11)) {
|
||||
guint32 val;
|
||||
|
||||
// handle either 0xHEX or dec
|
||||
if (*((*argv)[i]+12) == 'x') {
|
||||
sscanf ((*argv)[i]+13, "%08x", &val);
|
||||
} else {
|
||||
sscanf ((*argv)[i]+11, "%d", &val);
|
||||
}
|
||||
|
||||
gst_debug_set_categories (val);
|
||||
gst_info_set_categories (val);
|
||||
|
||||
(*argv)[i] = NULL;
|
||||
}
|
||||
else if (!strncmp ("--gst-plugin-spew", (*argv)[i], 17)) {
|
||||
_gst_plugin_spew = TRUE;
|
||||
|
||||
|
@ -247,10 +232,19 @@ gst_init_check (int *argc,
|
|||
g_print ("--------------------------------------------------------\n");
|
||||
|
||||
for (i = 0; i<GST_CAT_MAX_CATEGORY; i++) {
|
||||
if (gst_get_category_name(i)) {
|
||||
#if GST_DEBUG_COLOR
|
||||
g_print (" 0x%08x %s%s \033[%sm%s\033[00m\n", 1<<i,
|
||||
(gst_info_get_categories() & (1<<i)?"(enabled)":" "),
|
||||
(gst_debug_get_categories() & (1<<i)?"/(enabled)":"/ "),
|
||||
_gst_category_colors[i], gst_get_category_name (i));
|
||||
#else
|
||||
g_print (" 0x%08x %s%s %s\n", 1<<i,
|
||||
(gst_info_get_categories() & (1<<i)?"(enabled)":" "),
|
||||
(gst_debug_get_categories() & (1<<i)?"/(enabled)":"/ "),
|
||||
gst_get_category_name (i));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ret = FALSE;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <glib.h>
|
||||
|
||||
#include <gst/gstversion.h>
|
||||
#include <gst/gsttypes.h>
|
||||
|
||||
#include <gst/gstinfo.h>
|
||||
#include <gst/gstobject.h>
|
||||
|
@ -48,6 +49,7 @@
|
|||
#include <gst/gsttrace.h>
|
||||
#include <gst/gstxml.h>
|
||||
#include <gst/cothreads.h>
|
||||
#include <gst/gstscheduler.h>
|
||||
|
||||
#include <gst/gstparse.h>
|
||||
|
||||
|
|
524
gst/gstbin.c
524
gst/gstbin.c
|
@ -46,7 +46,6 @@ static gboolean gst_bin_change_state_type (GstBin *bin,
|
|||
GstElementState state,
|
||||
GtkType type);
|
||||
|
||||
static void gst_bin_create_plan_func (GstBin *bin);
|
||||
static gboolean gst_bin_iterate_func (GstBin *bin);
|
||||
|
||||
static xmlNodePtr gst_bin_save_thyself (GstObject *object, xmlNodePtr parent);
|
||||
|
@ -113,8 +112,6 @@ gst_bin_class_init (GstBinClass *klass)
|
|||
gtk_object_class_add_signals (gtkobject_class, gst_bin_signals, LAST_SIGNAL);
|
||||
|
||||
klass->change_state_type = gst_bin_change_state_type;
|
||||
klass->create_plan = gst_bin_create_plan_func;
|
||||
klass->schedule = gst_bin_schedule_func;
|
||||
klass->iterate = gst_bin_iterate_func;
|
||||
|
||||
gstobject_class->save_thyself = gst_bin_save_thyself;
|
||||
|
@ -155,6 +152,105 @@ gst_bin_new (const gchar *name)
|
|||
return gst_elementfactory_make ("bin", name);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gst_bin_reset_element_sched (GstElement *element, GstSchedule *sched)
|
||||
{
|
||||
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "resetting element's scheduler");
|
||||
|
||||
// first remove the element from its current schedule, if any
|
||||
// if (GST_ELEMENT_SCHED(element))
|
||||
// GST_SCHEDULE_REMOVE_ELEMENT (GST_ELEMENT_SCHED(element), element);
|
||||
// then set the new manager
|
||||
gst_element_set_sched (element,sched);
|
||||
|
||||
// and add it to the new scheduler
|
||||
// if (sched)
|
||||
// GST_SCHEDULE_ADD_ELEMENT (sched, element);
|
||||
}
|
||||
|
||||
void
|
||||
gst_bin_set_element_sched (GstElement *element,GstSchedule *sched)
|
||||
{
|
||||
GList *children;
|
||||
GstElement *child;
|
||||
|
||||
g_return_if_fail (element != NULL);
|
||||
g_return_if_fail (GST_IS_ELEMENT(element));
|
||||
g_return_if_fail (sched != NULL);
|
||||
g_return_if_fail (GST_IS_SCHEDULE(sched));
|
||||
|
||||
GST_INFO (GST_CAT_SCHEDULING, "setting element \"%s\" sched to %p",GST_ELEMENT_NAME(element),
|
||||
sched);
|
||||
|
||||
// if it's actually a Bin
|
||||
if (GST_IS_BIN(element)) {
|
||||
|
||||
if (GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
|
||||
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not resetting");
|
||||
return;
|
||||
}
|
||||
|
||||
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting children's schedule to parent's");
|
||||
GST_SCHEDULE_ADD_ELEMENT (sched, element);
|
||||
|
||||
// set the children's schedule
|
||||
children = GST_BIN(element)->children;
|
||||
while (children) {
|
||||
child = GST_ELEMENT (children->data);
|
||||
children = g_list_next(children);
|
||||
|
||||
gst_bin_set_element_sched (child, sched);
|
||||
}
|
||||
|
||||
// otherwise, if it's just a regular old element
|
||||
} else {
|
||||
GST_SCHEDULE_ADD_ELEMENT (sched, element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gst_bin_unset_element_sched (GstElement *element)
|
||||
{
|
||||
GList *children;
|
||||
GstElement *child;
|
||||
|
||||
g_return_if_fail (element != NULL);
|
||||
g_return_if_fail (GST_IS_ELEMENT(element));
|
||||
|
||||
GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from it sched %p",
|
||||
GST_ELEMENT_NAME(element),GST_ELEMENT_SCHED(element));
|
||||
|
||||
// if it's actually a Bin
|
||||
if (GST_IS_BIN(element)) {
|
||||
|
||||
if (GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
|
||||
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not unsetting sched");
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME this check should be irrelevant
|
||||
if (GST_ELEMENT_SCHED (element))
|
||||
GST_SCHEDULE_REMOVE_ELEMENT (GST_ELEMENT_SCHED(element), element);
|
||||
|
||||
// for each child, remove them from their schedule
|
||||
children = GST_BIN(element)->children;
|
||||
while (children) {
|
||||
child = GST_ELEMENT (children->data);
|
||||
children = g_list_next(children);
|
||||
|
||||
gst_bin_unset_element_sched (child);
|
||||
}
|
||||
|
||||
// otherwise, if it's just a regular old element
|
||||
} else {
|
||||
// FIXME this check should be irrelevant
|
||||
if (GST_ELEMENT_SCHED (element))
|
||||
GST_SCHEDULE_REMOVE_ELEMENT (GST_ELEMENT_SCHED(element), element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_bin_add:
|
||||
* @bin: #GstBin to add element to
|
||||
|
@ -172,19 +268,30 @@ gst_bin_add (GstBin *bin,
|
|||
g_return_if_fail (element != NULL);
|
||||
g_return_if_fail (GST_IS_ELEMENT (element));
|
||||
|
||||
// must be NULL or PAUSED state in order to modify bin
|
||||
g_return_if_fail ((GST_STATE (bin) == GST_STATE_NULL) ||
|
||||
(GST_STATE (bin) == GST_STATE_PAUSED));
|
||||
GST_DEBUG (GST_CAT_PARENTAGE, "adding element \"%s\" to bin \"%s\"\n",
|
||||
GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(bin));
|
||||
|
||||
// must be not be in PLAYING state in order to modify bin
|
||||
// g_return_if_fail (GST_STATE (bin) != GST_STATE_PLAYING);
|
||||
|
||||
// the element must not already have a parent
|
||||
g_return_if_fail (GST_ELEMENT_PARENT(element) == NULL);
|
||||
|
||||
// then check to see if the element's name is already taken in the bin
|
||||
g_return_if_fail (gst_object_check_uniqueness (bin->children, GST_ELEMENT_NAME(element)) == TRUE);
|
||||
|
||||
// set the element's parent and add the element to the bin's list of children
|
||||
gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
|
||||
bin->children = g_list_append (bin->children, element);
|
||||
bin->numchildren++;
|
||||
gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
|
||||
|
||||
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child %s", GST_ELEMENT_NAME (element));
|
||||
///// now we have to deal with manager stuff
|
||||
// we can only do this if there's a scheduler:
|
||||
// if we're not a manager, and aren't attached to anything, we have no sched (yet)
|
||||
if (GST_ELEMENT_SCHED(bin) != NULL)
|
||||
gst_bin_set_element_sched (element, GST_ELEMENT_SCHED(bin));
|
||||
|
||||
/* we know we have at least one child, we just added one... */
|
||||
// if (GST_STATE(element) < GST_STATE_READY)
|
||||
// gst_bin_change_state_norecurse(bin,GST_STATE_READY);
|
||||
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child \"%s\"", GST_ELEMENT_NAME (element));
|
||||
|
||||
gtk_signal_emit (GTK_OBJECT (bin), gst_bin_signals[OBJECT_ADDED], element);
|
||||
}
|
||||
|
@ -206,24 +313,32 @@ gst_bin_remove (GstBin *bin,
|
|||
g_return_if_fail (GST_IS_ELEMENT (element));
|
||||
g_return_if_fail (bin->children != NULL);
|
||||
|
||||
// must be NULL or PAUSED state in order to modify bin
|
||||
g_return_if_fail ((GST_STATE (bin) == GST_STATE_NULL) ||
|
||||
(GST_STATE (bin) == GST_STATE_PAUSED));
|
||||
// must not be in PLAYING state in order to modify bin
|
||||
g_return_if_fail (GST_STATE (bin) != GST_STATE_PLAYING);
|
||||
|
||||
// the element must have its parent set to the current bin
|
||||
g_return_if_fail (GST_ELEMENT_PARENT(element) == (GstObject *)bin);
|
||||
|
||||
// the element must be in the bin's list of children
|
||||
if (g_list_find(bin->children, element) == NULL) {
|
||||
// FIXME this should be a warning!!!
|
||||
GST_ERROR_OBJECT(bin,element,"no such element in bin");
|
||||
return;
|
||||
}
|
||||
|
||||
gst_object_unparent (GST_OBJECT (element));
|
||||
// remove this element from the list of managed elements
|
||||
gst_bin_unset_element_sched (element);
|
||||
|
||||
// now remove the element from the list of elements
|
||||
bin->children = g_list_remove (bin->children, element);
|
||||
bin->numchildren--;
|
||||
|
||||
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "removed child %s", GST_ELEMENT_NAME (element));
|
||||
|
||||
gst_object_unparent (GST_OBJECT (element));
|
||||
|
||||
/* if we're down to zero children, force state to NULL */
|
||||
if (bin->numchildren == 0)
|
||||
if (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL)
|
||||
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
|
||||
}
|
||||
|
||||
|
@ -236,62 +351,47 @@ gst_bin_change_state (GstElement *element)
|
|||
GstElement *child;
|
||||
GstElementStateReturn ret;
|
||||
|
||||
GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (element));
|
||||
// GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (element));
|
||||
|
||||
g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
|
||||
|
||||
bin = GST_BIN (element);
|
||||
|
||||
// GST_DEBUG (0,"currently %d(%s), %d(%s) pending\n",GST_STATE (element),
|
||||
// _gst_print_statename (GST_STATE (element)), GST_STATE_PENDING (element),
|
||||
// _gst_print_statename (GST_STATE_PENDING (element)));
|
||||
// GST_DEBUG (GST_CAT_STATES,"currently %d(%s), %d(%s) pending\n",GST_STATE (element),
|
||||
// gst_element_statename (GST_STATE (element)), GST_STATE_PENDING (element),
|
||||
// gst_element_statename (GST_STATE_PENDING (element)));
|
||||
|
||||
GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing bin's state from %s to %s",
|
||||
_gst_print_statename (GST_STATE (element)),
|
||||
_gst_print_statename (GST_STATE_PENDING (element)));
|
||||
GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing childrens' state from %s to %s",
|
||||
gst_element_statename (GST_STATE (element)),
|
||||
gst_element_statename (GST_STATE_PENDING (element)));
|
||||
|
||||
// g_return_val_if_fail(bin->numchildren != 0, GST_STATE_FAILURE);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
{
|
||||
GstObject *parent;
|
||||
|
||||
parent = gst_object_get_parent (GST_OBJECT (element));
|
||||
|
||||
if (!parent || !GST_IS_BIN (parent))
|
||||
gst_bin_create_plan (bin);
|
||||
else
|
||||
GST_DEBUG (0,"not creating plan for '%s'\n",GST_ELEMENT_NAME (bin));
|
||||
|
||||
break;
|
||||
}
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
GST_FLAG_UNSET (bin, GST_BIN_FLAG_MANAGER);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// g_print("-->\n");
|
||||
children = bin->children;
|
||||
while (children) {
|
||||
child = GST_ELEMENT (children->data);
|
||||
GST_DEBUG (0,"setting state on '%s'\n",GST_ELEMENT_NAME (child));
|
||||
// GST_DEBUG (GST_CAT_STATES,"setting state on '%s'\n",GST_ELEMENT_NAME (child));
|
||||
switch (gst_element_set_state (child, GST_STATE_PENDING (element))) {
|
||||
case GST_STATE_FAILURE:
|
||||
GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING;
|
||||
GST_DEBUG (0,"child '%s' failed to go to state %d(%s)\n", GST_ELEMENT_NAME (child),
|
||||
GST_STATE_PENDING (element), _gst_print_statename (GST_STATE_PENDING (element)));
|
||||
GST_DEBUG (GST_CAT_STATES,"child '%s' failed to go to state %d(%s)\n", GST_ELEMENT_NAME (child),
|
||||
GST_STATE_PENDING (element), gst_element_statename (GST_STATE_PENDING (element)));
|
||||
return GST_STATE_FAILURE;
|
||||
break;
|
||||
case GST_STATE_ASYNC:
|
||||
GST_DEBUG (0,"child '%s' is changing state asynchronously\n", GST_ELEMENT_NAME (child));
|
||||
GST_DEBUG (GST_CAT_STATES,"child '%s' is changing state asynchronously\n", GST_ELEMENT_NAME (child));
|
||||
break;
|
||||
}
|
||||
// g_print("\n");
|
||||
children = g_list_next (children);
|
||||
}
|
||||
// g_print("<-- \"%s\"\n",gst_object_get_name(GST_OBJECT(bin)));
|
||||
// g_print("<-- \"%s\"\n",GST_OBJECT_NAME(bin));
|
||||
|
||||
GST_INFO_ELEMENT (GST_CAT_STATES, element, "done changing bin's state from %s to %s",
|
||||
gst_element_statename (GST_STATE (element)),
|
||||
gst_element_statename (GST_STATE_PENDING (element)));
|
||||
ret = gst_bin_change_state_norecurse (bin);
|
||||
|
||||
return ret;
|
||||
|
@ -301,10 +401,10 @@ gst_bin_change_state (GstElement *element)
|
|||
static GstElementStateReturn
|
||||
gst_bin_change_state_norecurse (GstBin *bin)
|
||||
{
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state) {
|
||||
GST_DEBUG_ELEMENT (GST_CAT_STATES, bin, "setting bin's own state\n");
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (bin));
|
||||
else
|
||||
} else
|
||||
return GST_STATE_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -317,7 +417,7 @@ gst_bin_change_state_type(GstBin *bin,
|
|||
GstElement *child;
|
||||
|
||||
// g_print("gst_bin_change_state_type(\"%s\",%d,%d);\n",
|
||||
// gst_object_get_name(GST_OBJECT(bin)),state,type);
|
||||
// GST_OBJECT_NAME(bin))),state,type);
|
||||
|
||||
g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
|
||||
g_return_val_if_fail (bin->numchildren != 0, FALSE);
|
||||
|
@ -359,7 +459,7 @@ gst_bin_set_state_type (GstBin *bin,
|
|||
{
|
||||
GstBinClass *oclass;
|
||||
|
||||
GST_DEBUG (0,"gst_bin_set_state_type(\"%s\",%d,%d)\n",
|
||||
GST_DEBUG (GST_CAT_STATES,"gst_bin_set_state_type(\"%s\",%d,%d)\n",
|
||||
GST_ELEMENT_NAME (bin), state,type);
|
||||
|
||||
g_return_val_if_fail (bin != NULL, FALSE);
|
||||
|
@ -376,20 +476,31 @@ static void
|
|||
gst_bin_real_destroy (GtkObject *object)
|
||||
{
|
||||
GstBin *bin = GST_BIN (object);
|
||||
GList *children;
|
||||
GList *children, *orig;
|
||||
GstElement *child;
|
||||
|
||||
GST_DEBUG (0,"in gst_bin_real_destroy()\n");
|
||||
GST_DEBUG (GST_CAT_REFCOUNTING,"destroy()\n");
|
||||
|
||||
children = bin->children;
|
||||
if (bin->children) {
|
||||
orig = children = g_list_copy (bin->children);
|
||||
while (children) {
|
||||
child = GST_ELEMENT (children->data);
|
||||
gst_element_destroy (child);
|
||||
//gst_object_unref (GST_OBJECT (child));
|
||||
//gst_object_unparent (GST_OBJECT (child));
|
||||
gst_bin_remove (bin, child);
|
||||
children = g_list_next (children);
|
||||
}
|
||||
|
||||
g_list_free (orig);
|
||||
g_list_free (bin->children);
|
||||
}
|
||||
bin->children = NULL;
|
||||
bin->numchildren = 0;
|
||||
|
||||
g_cond_free (bin->eoscond);
|
||||
|
||||
if (GTK_OBJECT_CLASS (parent_class)->destroy)
|
||||
GTK_OBJECT_CLASS (parent_class)->destroy (object);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_bin_get_by_name:
|
||||
|
@ -416,7 +527,7 @@ gst_bin_get_by_name (GstBin *bin,
|
|||
children = bin->children;
|
||||
while (children) {
|
||||
child = GST_ELEMENT (children->data);
|
||||
if (!strcmp (gst_object_get_name (GST_OBJECT (child)),name))
|
||||
if (!strcmp (GST_OBJECT_NAME(child),name))
|
||||
return child;
|
||||
if (GST_IS_BIN (child)) {
|
||||
GstElement *res = gst_bin_get_by_name (GST_BIN (child), name);
|
||||
|
@ -521,7 +632,7 @@ gst_bin_restore_thyself (GstObject *object,
|
|||
childlist = field->xmlChildrenNode;
|
||||
while (childlist) {
|
||||
if (!strcmp (childlist->name, "element")) {
|
||||
GstElement *element = gst_element_load_thyself (childlist, GST_OBJECT (bin));
|
||||
GstElement *element = gst_element_restore_thyself (childlist, GST_OBJECT (bin));
|
||||
|
||||
gst_bin_add (bin, element);
|
||||
}
|
||||
|
@ -569,23 +680,6 @@ gst_bin_iterate (GstBin *bin)
|
|||
return eos;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_bin_create_plan:
|
||||
* @bin: #GstBin to create the plan for
|
||||
*
|
||||
* Let the bin figure out how to handle its children.
|
||||
*/
|
||||
void
|
||||
gst_bin_create_plan (GstBin *bin)
|
||||
{
|
||||
GstBinClass *oclass;
|
||||
|
||||
oclass = GST_BIN_CLASS (GTK_OBJECT (bin)->klass);
|
||||
|
||||
if (oclass->create_plan)
|
||||
(oclass->create_plan) (bin);
|
||||
}
|
||||
|
||||
/* out internal element fired EOS, we decrement the number of pending EOS childs */
|
||||
static void
|
||||
gst_bin_received_eos (GstElement *element, GstBin *bin)
|
||||
|
@ -601,290 +695,22 @@ gst_bin_received_eos (GstElement *element, GstBin *bin)
|
|||
GST_UNLOCK (bin);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_bin_schedule:
|
||||
* @bin: #GstBin to schedule
|
||||
*
|
||||
* Let the bin figure out how to handle its children.
|
||||
*/
|
||||
void
|
||||
gst_bin_schedule (GstBin *bin)
|
||||
{
|
||||
GstBinClass *oclass;
|
||||
|
||||
oclass = GST_BIN_CLASS (GTK_OBJECT (bin)->klass);
|
||||
|
||||
if (oclass->schedule)
|
||||
(oclass->schedule) (bin);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
gulong offset;
|
||||
gulong size;
|
||||
} region_struct;
|
||||
|
||||
|
||||
static void
|
||||
gst_bin_create_plan_func (GstBin *bin)
|
||||
{
|
||||
GstElement *manager;
|
||||
GList *elements;
|
||||
GstElement *element;
|
||||
#ifdef GST_DEBUG_ENABLED
|
||||
const gchar *elementname;
|
||||
#endif
|
||||
GSList *pending = NULL;
|
||||
GstBin *pending_bin;
|
||||
|
||||
GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (bin));
|
||||
|
||||
GST_INFO_ELEMENT (GST_CAT_PLANNING, bin, "creating plan");
|
||||
|
||||
// first figure out which element is the manager of this and all child elements
|
||||
// if we're a managing bin ourselves, that'd be us
|
||||
if (GST_FLAG_IS_SET (bin, GST_BIN_FLAG_MANAGER)) {
|
||||
manager = GST_ELEMENT (bin);
|
||||
GST_DEBUG (0,"setting manager to self\n");
|
||||
// otherwise, it's what our parent says it is
|
||||
} else {
|
||||
manager = gst_element_get_manager (GST_ELEMENT (bin));
|
||||
if (!manager) {
|
||||
GST_DEBUG (0,"manager not set for element \"%s\" assuming manager is self\n", GST_ELEMENT_NAME (bin));
|
||||
manager = GST_ELEMENT (bin);
|
||||
GST_FLAG_SET (bin, GST_BIN_FLAG_MANAGER);
|
||||
}
|
||||
GST_DEBUG (0,"setting manager to \"%s\"\n", GST_ELEMENT_NAME (manager));
|
||||
}
|
||||
gst_element_set_manager (GST_ELEMENT (bin), manager);
|
||||
|
||||
// perform the first recursive pass of plan generation
|
||||
// we set the manager of every element but those who manage themselves
|
||||
// the need for cothreads is also determined recursively
|
||||
GST_DEBUG (0,"performing first-phase recursion\n");
|
||||
bin->need_cothreads = bin->use_cothreads;
|
||||
if (bin->need_cothreads)
|
||||
GST_DEBUG (0,"requiring cothreads because we're forced to\n");
|
||||
|
||||
elements = bin->children;
|
||||
while (elements) {
|
||||
element = GST_ELEMENT (elements->data);
|
||||
elements = g_list_next (elements);
|
||||
#ifdef GST_DEBUG_ENABLED
|
||||
elementname = GST_ELEMENT_NAME (element);
|
||||
#endif
|
||||
GST_DEBUG (0,"have element \"%s\"\n",elementname);
|
||||
|
||||
// first set their manager
|
||||
GST_DEBUG (0,"setting manager of \"%s\" to \"%s\"\n",elementname,GST_ELEMENT_NAME (manager));
|
||||
gst_element_set_manager (element, manager);
|
||||
|
||||
// we do recursion and such for Bins
|
||||
if (GST_IS_BIN (element)) {
|
||||
// recurse into the child Bin
|
||||
GST_DEBUG (0,"recursing into child Bin \"%s\" with manager \"%s\"\n",elementname,
|
||||
GST_ELEMENT_NAME (element->manager));
|
||||
gst_bin_create_plan (GST_BIN (element));
|
||||
GST_DEBUG (0,"after recurse got manager \"%s\"\n",
|
||||
GST_ELEMENT_NAME (element->manager));
|
||||
// check to see if it needs cothreads and isn't self-managing
|
||||
if (((GST_BIN (element))->need_cothreads) && !GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
|
||||
GST_DEBUG (0,"requiring cothreads because child bin \"%s\" does\n",elementname);
|
||||
bin->need_cothreads = TRUE;
|
||||
}
|
||||
} else {
|
||||
// then we need to determine whether they need cothreads
|
||||
// if it's a loop-based element, use cothreads
|
||||
if (element->loopfunc != NULL) {
|
||||
GST_DEBUG (0,"requiring cothreads because \"%s\" is a loop-based element\n",elementname);
|
||||
GST_FLAG_SET (element, GST_ELEMENT_USE_COTHREAD);
|
||||
// if it's a 'complex' element, use cothreads
|
||||
} else if (GST_FLAG_IS_SET (element, GST_ELEMENT_COMPLEX)) {
|
||||
GST_DEBUG (0,"requiring cothreads because \"%s\" is complex\n",elementname);
|
||||
GST_FLAG_SET (element, GST_ELEMENT_USE_COTHREAD);
|
||||
// if the element has more than one sink pad, use cothreads
|
||||
} else if (element->numsinkpads > 1) {
|
||||
GST_DEBUG (0,"requiring cothreads because \"%s\" has more than one sink pad\n",elementname);
|
||||
GST_FLAG_SET (element, GST_ELEMENT_USE_COTHREAD);
|
||||
}
|
||||
if (GST_FLAG_IS_SET (element, GST_ELEMENT_USE_COTHREAD))
|
||||
bin->need_cothreads = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if we're not a manager thread, we're done.
|
||||
if (!GST_FLAG_IS_SET (bin, GST_BIN_FLAG_MANAGER)) {
|
||||
GST_DEBUG_LEAVE("(\"%s\")",GST_ELEMENT_NAME (bin));
|
||||
return;
|
||||
}
|
||||
|
||||
// clear previous plan state
|
||||
g_list_free (bin->managed_elements);
|
||||
bin->managed_elements = NULL;
|
||||
bin->num_managed_elements = 0;
|
||||
|
||||
// find all the managed children
|
||||
// here we pull off the trick of walking an entire arbitrary tree without recursion
|
||||
GST_DEBUG (0,"attempting to find all the elements to manage\n");
|
||||
pending = g_slist_prepend (pending, bin);
|
||||
do {
|
||||
// retrieve the top of the stack and pop it
|
||||
pending_bin = GST_BIN (pending->data);
|
||||
pending = g_slist_remove (pending, pending_bin);
|
||||
|
||||
// walk the list of elements, find bins, and do stuff
|
||||
GST_DEBUG (0,"checking Bin \"%s\" for managed elements\n",
|
||||
GST_ELEMENT_NAME (pending_bin));
|
||||
elements = pending_bin->children;
|
||||
while (elements) {
|
||||
element = GST_ELEMENT (elements->data);
|
||||
elements = g_list_next (elements);
|
||||
#ifdef GST_DEBUG_ENABLED
|
||||
elementname = GST_ELEMENT_NAME (element);
|
||||
#endif
|
||||
|
||||
// if it's ours, add it to the list
|
||||
if (element->manager == GST_ELEMENT(bin)) {
|
||||
// if it's a Bin, add it to the list of Bins to check
|
||||
if (GST_IS_BIN (element)) {
|
||||
GST_DEBUG (0,"flattened recurse into \"%s\"\n",elementname);
|
||||
pending = g_slist_prepend (pending, element);
|
||||
|
||||
// otherwise add it to the list of elements
|
||||
} else {
|
||||
GST_DEBUG (0,"found element \"%s\" that I manage\n",elementname);
|
||||
bin->managed_elements = g_list_prepend (bin->managed_elements, element);
|
||||
bin->num_managed_elements++;
|
||||
}
|
||||
}
|
||||
// else it's not ours and we need to wait for EOS notifications
|
||||
else {
|
||||
GST_DEBUG (0,"setting up EOS signal from \"%s\" to \"%s\"\n", elementname,
|
||||
gst_element_get_name (GST_ELEMENT(bin)->manager));
|
||||
gtk_signal_connect (GTK_OBJECT (element), "eos", gst_bin_received_eos, GST_ELEMENT(bin)->manager);
|
||||
bin->eos_providers = g_list_prepend (bin->eos_providers, element);
|
||||
bin->num_eos_providers++;
|
||||
}
|
||||
}
|
||||
} while (pending);
|
||||
|
||||
GST_DEBUG (0,"have %d elements to manage, implementing plan\n",bin->num_managed_elements);
|
||||
|
||||
gst_bin_schedule(bin);
|
||||
|
||||
// g_print ("gstbin \"%s\", eos providers:%d\n",
|
||||
// GST_ELEMENT_NAME (bin),
|
||||
// bin->num_eos_providers);
|
||||
|
||||
GST_DEBUG_LEAVE("(\"%s\")",GST_ELEMENT_NAME (bin));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_bin_iterate_func (GstBin *bin)
|
||||
{
|
||||
GList *chains;
|
||||
_GstBinChain *chain;
|
||||
GList *entries;
|
||||
GstElement *entry;
|
||||
GList *pads;
|
||||
GstPad *pad;
|
||||
GstBuffer *buf = NULL;
|
||||
gint num_scheduled = 0;
|
||||
gboolean eos = FALSE;
|
||||
|
||||
GST_DEBUG_ENTER("(\"%s\")", GST_ELEMENT_NAME (bin));
|
||||
|
||||
g_return_val_if_fail (bin != NULL, TRUE);
|
||||
g_return_val_if_fail (GST_IS_BIN (bin), TRUE);
|
||||
g_return_val_if_fail (GST_STATE (bin) == GST_STATE_PLAYING, TRUE);
|
||||
|
||||
// step through all the chains
|
||||
chains = bin->chains;
|
||||
while (chains) {
|
||||
chain = (_GstBinChain *)(chains->data);
|
||||
chains = g_list_next (chains);
|
||||
|
||||
if (!chain->need_scheduling) continue;
|
||||
|
||||
if (chain->need_cothreads) {
|
||||
GList *entries;
|
||||
|
||||
// all we really have to do is switch to the first child
|
||||
// FIXME this should be lots more intelligent about where to start
|
||||
GST_DEBUG (0,"starting iteration via cothreads\n");
|
||||
|
||||
entries = chain->elements;
|
||||
entry = NULL;
|
||||
|
||||
// find an element with a threadstate to start with
|
||||
while (entries) {
|
||||
entry = GST_ELEMENT (entries->data);
|
||||
|
||||
if (entry->threadstate)
|
||||
break;
|
||||
entries = g_list_next (entries);
|
||||
}
|
||||
// if we couldn't find one, bail out
|
||||
if (entries == NULL)
|
||||
GST_ERROR(GST_ELEMENT(bin),"no cothreaded elements found!");
|
||||
|
||||
GST_FLAG_SET (entry, GST_ELEMENT_COTHREAD_STOPPING);
|
||||
GST_DEBUG (0,"set COTHREAD_STOPPING flag on \"%s\"(@%p)\n",
|
||||
GST_ELEMENT_NAME (entry),entry);
|
||||
cothread_switch (entry->threadstate);
|
||||
|
||||
// only iterate if this is the manager bin
|
||||
if (GST_ELEMENT_SCHED(bin)->parent == GST_ELEMENT (bin)) {
|
||||
return GST_SCHEDULE_ITERATE(GST_ELEMENT_SCHED(bin));
|
||||
} else {
|
||||
GST_DEBUG (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++;
|
||||
GST_DEBUG (GST_CAT_SCHEDULING, "this bin can't be iterated on!\n");
|
||||
}
|
||||
|
||||
// check if nothing was scheduled that was ours..
|
||||
if (!num_scheduled) {
|
||||
// are there any other elements that are still busy?
|
||||
if (bin->num_eos_providers) {
|
||||
GST_LOCK (bin);
|
||||
GST_DEBUG (0,"waiting for eos providers\n");
|
||||
g_cond_wait (bin->eoscond, GST_GET_LOCK(bin));
|
||||
GST_DEBUG (0,"num eos providers %d\n", bin->num_eos_providers);
|
||||
GST_UNLOCK (bin);
|
||||
}
|
||||
else {
|
||||
gst_element_signal_eos (GST_ELEMENT (bin));
|
||||
eos = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
GST_DEBUG_LEAVE("(%s)", GST_ELEMENT_NAME (bin));
|
||||
return !eos;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
15
gst/gstbin.h
15
gst/gstbin.h
|
@ -47,6 +47,8 @@ extern GstElementDetails gst_bin_details;
|
|||
typedef enum {
|
||||
/* this bin is a manager of child elements, i.e. a pipeline or thread */
|
||||
GST_BIN_FLAG_MANAGER = GST_ELEMENT_FLAG_LAST,
|
||||
/* this bin is actually a meta-bin, and may need to be scheduled */
|
||||
GST_BIN_SELF_SCHEDULABLE,
|
||||
|
||||
/* we prefer to have cothreads when its an option, over chain-based */
|
||||
GST_BIN_FLAG_PREFER_COTHREADS,
|
||||
|
@ -55,8 +57,8 @@ typedef enum {
|
|||
GST_BIN_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 4,
|
||||
} GstBinFlags;
|
||||
|
||||
typedef struct _GstBin GstBin;
|
||||
typedef struct _GstBinClass GstBinClass;
|
||||
//typedef struct _GstBin GstBin;
|
||||
//typedef struct _GstBinClass GstBinClass;
|
||||
typedef struct __GstBinChain _GstBinChain;
|
||||
|
||||
struct _GstBin {
|
||||
|
@ -94,9 +96,6 @@ struct _GstBinClass {
|
|||
gboolean (*change_state_type) (GstBin *bin,
|
||||
GstElementState state,
|
||||
GtkType type);
|
||||
/* create a plan for the execution of the bin */
|
||||
void (*create_plan) (GstBin *bin);
|
||||
void (*schedule) (GstBin *bin);
|
||||
/* run a full iteration of operation */
|
||||
gboolean (*iterate) (GstBin *bin);
|
||||
};
|
||||
|
@ -116,6 +115,10 @@ GtkType gst_bin_get_type (void);
|
|||
GstElement* gst_bin_new (const gchar *name);
|
||||
#define gst_bin_destroy(bin) gst_object_destroy(GST_OBJECT(bin))
|
||||
|
||||
void gst_bin_set_element_manager (GstElement *element, GstElement *manager);
|
||||
void gst_bin_add_managed_element (GstBin *bin, GstElement *element);
|
||||
void gst_bin_remove_managed_element (GstBin *bin, GstElement *element);
|
||||
|
||||
/* add and remove elements from the bin */
|
||||
void gst_bin_add (GstBin *bin,
|
||||
GstElement *element);
|
||||
|
@ -129,8 +132,6 @@ GstElement* gst_bin_get_by_name_recurse_up (GstBin *bin,
|
|||
const gchar *name);
|
||||
GList* gst_bin_get_list (GstBin *bin);
|
||||
|
||||
void gst_bin_create_plan (GstBin *bin);
|
||||
void gst_bin_schedule (GstBin *bin);
|
||||
gboolean gst_bin_set_state_type (GstBin *bin,
|
||||
GstElementState state,
|
||||
GtkType type);
|
||||
|
|
|
@ -448,7 +448,7 @@ gst_buffer_copy (GstBuffer *buffer)
|
|||
// copy the absolute size
|
||||
newbuf->size = buffer->size;
|
||||
// allocate space for the copy
|
||||
newbuf->data = (guchar *)g_malloc (buffer->data);
|
||||
newbuf->data = (guchar *)g_malloc (buffer->size);
|
||||
// copy the data straight across
|
||||
memcpy(newbuf,buffer->data,buffer->size);
|
||||
// the new maxsize is the same as the size, since we just malloc'd it
|
||||
|
|
|
@ -476,7 +476,7 @@ static gboolean
|
|||
gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
|
||||
{
|
||||
if (fromcaps->id != tocaps->id) {
|
||||
GST_DEBUG (0,"gstcaps: mime types differ (%s to %s)\n",
|
||||
GST_DEBUG (GST_CAT_CAPS,"mime types differ (%s to %s)\n",
|
||||
gst_type_find_by_id (fromcaps->id)->mime,
|
||||
gst_type_find_by_id (tocaps->id)->mime);
|
||||
return FALSE;
|
||||
|
@ -487,13 +487,13 @@ gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
|
|||
return gst_props_check_compatibility (fromcaps->properties, tocaps->properties);
|
||||
}
|
||||
else {
|
||||
GST_DEBUG (0,"gstcaps: no source caps\n");
|
||||
GST_DEBUG (GST_CAT_CAPS,"no source caps\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// assume it accepts everything
|
||||
GST_DEBUG (0,"gstcaps: no caps\n");
|
||||
GST_DEBUG (GST_CAT_CAPS,"no caps\n");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -512,17 +512,17 @@ gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps)
|
|||
{
|
||||
if (fromcaps == NULL) {
|
||||
if (tocaps == NULL) {
|
||||
GST_DEBUG (0,"gstcaps: no caps\n");
|
||||
GST_DEBUG (GST_CAT_CAPS,"no caps\n");
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
GST_DEBUG (0,"gstcaps: no src but destination caps\n");
|
||||
GST_DEBUG (GST_CAT_CAPS,"no source but destination caps\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (tocaps == NULL) {
|
||||
GST_DEBUG (0,"gstcaps: src caps and no dest caps\n");
|
||||
GST_DEBUG (GST_CAT_CAPS,"source caps and no destination caps\n");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ void
|
|||
gst_clock_register (GstClock *clock, GstObject *obj)
|
||||
{
|
||||
if ((GST_ELEMENT(obj))->numsrcpads == 0) {
|
||||
GST_DEBUG (0,"gst_clock: setting registered sink object 0x%p\n", obj);
|
||||
GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting registered sink object 0x%p\n", obj);
|
||||
clock->sinkobjects = g_list_append (clock->sinkobjects, obj);
|
||||
clock->num++;
|
||||
}
|
||||
|
@ -88,7 +88,8 @@ gst_clock_set (GstClock *clock, GstClockTime time)
|
|||
g_mutex_lock (clock->lock);
|
||||
clock->start_time = now - time;
|
||||
g_mutex_unlock (clock->lock);
|
||||
GST_DEBUG (0,"gst_clock: setting clock to %llu %llu %llu\n", time, now, clock->start_time);
|
||||
GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting clock to %llu %llu %llu\n",
|
||||
time, now, clock->start_time);
|
||||
}
|
||||
|
||||
GstClockTimeDiff
|
||||
|
@ -115,7 +116,7 @@ gst_clock_reset (GstClock *clock)
|
|||
clock->start_time = ((guint64)tfnow.tv_sec)*1000000LL+tfnow.tv_usec;
|
||||
clock->current_time = clock->start_time;
|
||||
clock->adjust = 0LL;
|
||||
GST_DEBUG (0,"gst_clock: setting start clock %llu\n", clock->start_time);
|
||||
GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting start clock %llu\n", clock->start_time);
|
||||
g_mutex_unlock (clock->lock);
|
||||
}
|
||||
|
||||
|
@ -133,7 +134,8 @@ gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj)
|
|||
|
||||
diff = GST_CLOCK_DIFF (time, now);
|
||||
// if we are not behind wait a bit
|
||||
GST_DEBUG (0,"gst_clock: %s waiting for time %08llu %08llu %08lld\n", GST_OBJECT_NAME (obj), time, now, diff);
|
||||
GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld\n",
|
||||
GST_OBJECT_NAME (obj), time, now, diff);
|
||||
|
||||
g_mutex_unlock (clock->lock);
|
||||
if (diff > 10000 ) {
|
||||
|
@ -143,8 +145,9 @@ gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj)
|
|||
if (!tfnow.tv_sec) {
|
||||
select(0, NULL, NULL, NULL, &tfnow);
|
||||
}
|
||||
else GST_DEBUG (0,"gst_clock: %s waiting %u %llu %llu %llu seconds\n", GST_OBJECT_NAME (obj),
|
||||
(int)tfnow.tv_sec, now, diff, time);
|
||||
else GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting %u %llu %llu %llu seconds\n",
|
||||
GST_OBJECT_NAME (obj), (int)tfnow.tv_sec, now, diff, time);
|
||||
}
|
||||
GST_DEBUG (0,"gst_clock: %s waiting for time %08llu %08llu %08lld done \n", GST_OBJECT_NAME (obj), time, now, diff);
|
||||
GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld done \n",
|
||||
GST_OBJECT_NAME (obj), time, now, diff);
|
||||
}
|
||||
|
|
264
gst/gstelement.c
264
gst/gstelement.c
|
@ -26,14 +26,16 @@
|
|||
#include "gstelement.h"
|
||||
#include "gstextratypes.h"
|
||||
#include "gstbin.h"
|
||||
#include "gstscheduler.h"
|
||||
#include "gstutils.h"
|
||||
|
||||
|
||||
/* Element signals and args */
|
||||
enum {
|
||||
STATE_CHANGE,
|
||||
NEW_PAD,
|
||||
PAD_REMOVED,
|
||||
NEW_GHOST_PAD,
|
||||
GHOST_PAD_REMOVED,
|
||||
ERROR,
|
||||
EOS,
|
||||
LAST_SIGNAL
|
||||
|
@ -48,6 +50,10 @@ enum {
|
|||
static void gst_element_class_init (GstElementClass *klass);
|
||||
static void gst_element_init (GstElement *element);
|
||||
|
||||
static void gst_element_set_arg (GtkObject *object, GtkArg *arg, guint id);
|
||||
static void gst_element_get_arg (GtkObject *object, GtkArg *arg, guint id);
|
||||
|
||||
static void gst_element_shutdown (GtkObject *object);
|
||||
static void gst_element_real_destroy (GtkObject *object);
|
||||
|
||||
static GstElementStateReturn gst_element_change_state (GstElement *element);
|
||||
|
@ -67,8 +73,8 @@ GtkType gst_element_get_type(void) {
|
|||
sizeof(GstElementClass),
|
||||
(GtkClassInitFunc)gst_element_class_init,
|
||||
(GtkObjectInitFunc)gst_element_init,
|
||||
(GtkArgSetFunc)NULL,
|
||||
(GtkArgGetFunc)NULL,
|
||||
(GtkArgSetFunc)gst_element_set_arg,
|
||||
(GtkArgGetFunc)gst_element_get_arg,
|
||||
(GtkClassInitFunc)NULL,
|
||||
};
|
||||
element_type = gtk_type_unique(GST_TYPE_OBJECT,&element_info);
|
||||
|
@ -97,11 +103,21 @@ gst_element_class_init (GstElementClass *klass)
|
|||
GTK_SIGNAL_OFFSET (GstElementClass, new_pad),
|
||||
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
|
||||
GST_TYPE_PAD);
|
||||
gst_element_signals[PAD_REMOVED] =
|
||||
gtk_signal_new ("pad_removed", GTK_RUN_LAST, gtkobject_class->type,
|
||||
GTK_SIGNAL_OFFSET (GstElementClass, pad_removed),
|
||||
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
|
||||
GST_TYPE_PAD);
|
||||
gst_element_signals[NEW_GHOST_PAD] =
|
||||
gtk_signal_new ("new_ghost_pad", GTK_RUN_LAST, gtkobject_class->type,
|
||||
GTK_SIGNAL_OFFSET (GstElementClass, new_ghost_pad),
|
||||
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
|
||||
GST_TYPE_PAD);
|
||||
gst_element_signals[GHOST_PAD_REMOVED] =
|
||||
gtk_signal_new ("ghost_pad_removed", GTK_RUN_LAST, gtkobject_class->type,
|
||||
GTK_SIGNAL_OFFSET (GstElementClass, ghost_pad_removed),
|
||||
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
|
||||
GST_TYPE_PAD);
|
||||
gst_element_signals[ERROR] =
|
||||
gtk_signal_new ("error", GTK_RUN_LAST, gtkobject_class->type,
|
||||
GTK_SIGNAL_OFFSET (GstElementClass, error),
|
||||
|
@ -115,11 +131,15 @@ gst_element_class_init (GstElementClass *klass)
|
|||
|
||||
gtk_object_class_add_signals (gtkobject_class, gst_element_signals, LAST_SIGNAL);
|
||||
|
||||
gtkobject_class->destroy = gst_element_real_destroy;
|
||||
gtkobject_class->set_arg = GST_DEBUG_FUNCPTR(gst_element_set_arg);
|
||||
gtkobject_class->get_arg = GST_DEBUG_FUNCPTR(gst_element_get_arg);
|
||||
gtkobject_class->shutdown = GST_DEBUG_FUNCPTR(gst_element_shutdown);
|
||||
gtkobject_class->destroy = GST_DEBUG_FUNCPTR(gst_element_real_destroy);
|
||||
|
||||
gstobject_class->save_thyself = gst_element_save_thyself;
|
||||
gstobject_class->save_thyself = GST_DEBUG_FUNCPTR(gst_element_save_thyself);
|
||||
gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR(gst_element_restore_thyself);
|
||||
|
||||
klass->change_state = gst_element_change_state;
|
||||
klass->change_state = GST_DEBUG_FUNCPTR(gst_element_change_state);
|
||||
klass->elementfactory = NULL;
|
||||
}
|
||||
|
||||
|
@ -134,8 +154,38 @@ gst_element_init (GstElement *element)
|
|||
element->pads = NULL;
|
||||
element->loopfunc = NULL;
|
||||
element->threadstate = NULL;
|
||||
element->sched = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_element_set_arg (GtkObject *object, GtkArg *arg, guint id)
|
||||
{
|
||||
GstElementClass *oclass = GST_ELEMENT_CLASS (object->klass);
|
||||
|
||||
GST_SCHEDULE_LOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
|
||||
|
||||
if (oclass->set_arg)
|
||||
(oclass->set_arg)(object,arg,id);
|
||||
|
||||
GST_SCHEDULE_UNLOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_element_get_arg (GtkObject *object, GtkArg *arg, guint id)
|
||||
{
|
||||
GstElementClass *oclass = GST_ELEMENT_CLASS (object->klass);
|
||||
|
||||
GST_SCHEDULE_LOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
|
||||
|
||||
if (oclass->get_arg)
|
||||
(oclass->get_arg)(object,arg,id);
|
||||
|
||||
GST_SCHEDULE_UNLOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_element_new:
|
||||
*
|
||||
|
@ -237,9 +287,15 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
|
|||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
|
||||
// first check to make sure the pad's parent is already set
|
||||
g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
|
||||
|
||||
// then check to see if there's already a pad by that name here
|
||||
g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
|
||||
|
||||
/* set the pad's parent */
|
||||
GST_DEBUG (0,"setting parent of pad '%s'(%p) to '%s'(%p)\n",
|
||||
GST_PAD_NAME (pad), pad, GST_ELEMENT_NAME (element), element);
|
||||
GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'\n",
|
||||
GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
|
||||
gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
|
||||
|
||||
/* add it to the list */
|
||||
|
@ -254,6 +310,36 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
|
|||
gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_PAD], pad);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_remove_pad:
|
||||
* @element: element to remove pad from
|
||||
* @pad: pad to remove
|
||||
*
|
||||
* Remove a pad (connection point) from the element,
|
||||
*/
|
||||
void
|
||||
gst_element_remove_pad (GstElement *element, GstPad *pad)
|
||||
{
|
||||
g_return_if_fail (element != NULL);
|
||||
g_return_if_fail (GST_IS_ELEMENT (element));
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
|
||||
g_return_if_fail (GST_PAD_PARENT (pad) == element);
|
||||
|
||||
/* add it to the list */
|
||||
element->pads = g_list_remove (element->pads, pad);
|
||||
element->numpads--;
|
||||
if (gst_pad_get_direction (pad) == GST_PAD_SRC)
|
||||
element->numsrcpads--;
|
||||
else
|
||||
element->numsinkpads--;
|
||||
|
||||
gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[PAD_REMOVED], pad);
|
||||
|
||||
gst_object_unparent (GST_OBJECT (pad));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_add_ghost_pad:
|
||||
* @element: element to add ghost pad to
|
||||
|
@ -273,17 +359,22 @@ gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name)
|
|||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
|
||||
GST_DEBUG(0,"creating new ghost pad called %s, from pad %s:%s\n",name,GST_DEBUG_PAD_NAME(pad));
|
||||
// then check to see if there's already a pad by that name here
|
||||
g_return_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE);
|
||||
|
||||
GST_DEBUG(GST_CAT_ELEMENT_PADS,"creating new ghost pad called %s, from pad %s:%s\n",
|
||||
name,GST_DEBUG_PAD_NAME(pad));
|
||||
ghostpad = gst_ghost_pad_new (name, pad);
|
||||
|
||||
/* add it to the list */
|
||||
GST_DEBUG(0,"adding ghost pad %s to element %s\n", name, GST_ELEMENT_NAME (element));
|
||||
GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s\n",
|
||||
name, GST_ELEMENT_NAME (element));
|
||||
element->pads = g_list_append (element->pads, ghostpad);
|
||||
element->numpads++;
|
||||
// set the parent of the ghostpad
|
||||
gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
|
||||
|
||||
GST_DEBUG(0,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
|
||||
GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
|
||||
|
||||
/* emit the NEW_GHOST_PAD signal */
|
||||
gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_GHOST_PAD], ghostpad);
|
||||
|
@ -331,21 +422,18 @@ gst_element_get_pad (GstElement *element, const gchar *name)
|
|||
if (!element->numpads)
|
||||
return NULL;
|
||||
|
||||
GST_DEBUG(GST_CAT_ELEMENT_PADS,"searching for pad '%s' in element %s\n",
|
||||
name, GST_ELEMENT_NAME (element));
|
||||
|
||||
// look through the list, matching by name
|
||||
walk = element->pads;
|
||||
while (walk) {
|
||||
GstPad *pad = GST_PAD(walk->data);
|
||||
if (!strcmp (gst_object_get_name (GST_OBJECT(pad)), name)) {
|
||||
GST_DEBUG(GST_CAT_ELEMENT_PADS,"found pad '%s'\n",name);
|
||||
if (!strcmp (GST_PAD_NAME(pad), name)) {
|
||||
GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad));
|
||||
return pad;
|
||||
}
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
|
||||
GST_DEBUG(GST_CAT_ELEMENT_PADS,"no such pad '%s'\n",name);
|
||||
GST_INFO(GST_CAT_ELEMENT_PADS,"no such pad '%s' in element \"%s\"",name,GST_ELEMENT_NAME(element));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -440,7 +528,7 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *
|
|||
GstPadTemplate *newtempl = NULL;
|
||||
GList *padlist;
|
||||
|
||||
GST_DEBUG(0,"gst_element_get_padtemplate_by_compatible()\n");
|
||||
GST_DEBUG(GST_CAT_ELEMENT_PADS,"gst_element_get_padtemplate_by_compatible()\n");
|
||||
|
||||
g_return_val_if_fail (element != NULL, NULL);
|
||||
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||
|
@ -457,19 +545,19 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *
|
|||
// Check direction (must be opposite)
|
||||
// Check caps
|
||||
|
||||
GST_DEBUG(0,"checking direction and caps\n");
|
||||
GST_DEBUG(GST_CAT_CAPS,"checking direction and caps\n");
|
||||
if (padtempl->direction == GST_PAD_SRC &&
|
||||
compattempl->direction == GST_PAD_SINK) {
|
||||
GST_DEBUG(0,"compatible direction: found src pad template\n");
|
||||
GST_DEBUG(GST_CAT_CAPS,"compatible direction: found src pad template\n");
|
||||
compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (padtempl),
|
||||
GST_PADTEMPLATE_CAPS (compattempl));
|
||||
GST_DEBUG(0,"caps are %scompatible\n", (compat?"":"not "));
|
||||
GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
|
||||
} else if (padtempl->direction == GST_PAD_SINK &&
|
||||
compattempl->direction == GST_PAD_SRC) {
|
||||
GST_DEBUG(0,"compatible direction: found sink pad template\n");
|
||||
GST_DEBUG(GST_CAT_CAPS,"compatible direction: found sink pad template\n");
|
||||
compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (compattempl),
|
||||
GST_PADTEMPLATE_CAPS (padtempl));
|
||||
GST_DEBUG(0,"caps are %scompatible\n", (compat?"":"not "));
|
||||
GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
|
||||
}
|
||||
|
||||
if (compat) {
|
||||
|
@ -659,7 +747,7 @@ gst_element_disconnect (GstElement *src, const gchar *srcpadname,
|
|||
void
|
||||
gst_element_error (GstElement *element, const gchar *error)
|
||||
{
|
||||
g_error("GstElement: error in element '%s': %s\n", gst_object_get_name (GST_OBJECT (element)), error);
|
||||
g_error("GstElement: error in element '%s': %s\n", GST_ELEMENT_NAME(element), error);
|
||||
|
||||
/* FIXME: this is not finished!!! */
|
||||
|
||||
|
@ -689,6 +777,11 @@ gst_element_set_state (GstElement *element, GstElementState state)
|
|||
|
||||
g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
|
||||
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
|
||||
g_return_val_if_fail (element->sched != NULL, GST_STATE_FAILURE);
|
||||
|
||||
GST_DEBUG_ELEMENT (GST_CAT_STATES,element, "setting state from %s to %s\n",
|
||||
gst_element_statename(GST_STATE(element)),
|
||||
gst_element_statename(state));
|
||||
|
||||
/* start with the current state */
|
||||
curpending = GST_STATE(element);
|
||||
|
@ -702,6 +795,9 @@ gst_element_set_state (GstElement *element, GstElementState state)
|
|||
/* set the pending state variable */
|
||||
// FIXME: should probably check to see that we don't already have one
|
||||
GST_STATE_PENDING (element) = curpending;
|
||||
if (curpending != state)
|
||||
GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"intermediate: setting state to %s\n",
|
||||
gst_element_statename(curpending));
|
||||
|
||||
/* call the state change function so it can set the state */
|
||||
oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
|
||||
|
@ -711,7 +807,7 @@ gst_element_set_state (GstElement *element, GstElementState state)
|
|||
/* if that outright didn't work, we need to bail right away */
|
||||
/* NOTE: this will bail on ASYNC as well! */
|
||||
if (return_val == GST_STATE_FAILURE) {
|
||||
// GST_DEBUG (0,"have async return from '%s'\n",GST_ELEMENT_NAME (element));
|
||||
GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"have failed change_state return\n");
|
||||
return return_val;
|
||||
}
|
||||
}
|
||||
|
@ -741,6 +837,7 @@ gst_element_get_factory (GstElement *element)
|
|||
return oclass->elementfactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_element_change_state:
|
||||
* @element: element to change state of
|
||||
|
@ -757,15 +854,48 @@ gst_element_change_state (GstElement *element)
|
|||
g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
|
||||
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
|
||||
|
||||
// g_print("gst_element_change_state(\"%s\",%d)\n",
|
||||
// element->name,state);
|
||||
// GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "default handler sets state to %s\n",
|
||||
// gst_element_statename(GST_STATE_PENDING(element)));
|
||||
|
||||
if (GST_STATE_TRANSITION(element) == GST_STATE_PAUSED_TO_PLAYING) {
|
||||
g_return_val_if_fail(GST_ELEMENT_SCHED(element), GST_STATE_FAILURE);
|
||||
if (GST_ELEMENT_PARENT(element))
|
||||
fprintf(stderr,"PAUSED->PLAYING: element \"%s\" has parent \"%s\" and sched %p\n",
|
||||
GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
|
||||
GST_SCHEDULE_ENABLE_ELEMENT (element->sched,element);
|
||||
}
|
||||
else if (GST_STATE_TRANSITION(element) == GST_STATE_PLAYING_TO_PAUSED) {
|
||||
if (GST_ELEMENT_PARENT(element))
|
||||
fprintf(stderr,"PLAYING->PAUSED: element \"%s\" has parent \"%s\" and sched %p\n",
|
||||
GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
|
||||
GST_SCHEDULE_DISABLE_ELEMENT (element->sched,element);
|
||||
}
|
||||
|
||||
GST_STATE (element) = GST_STATE_PENDING (element);
|
||||
GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING;
|
||||
|
||||
// note: queues' state_change is a special case because it needs to lock
|
||||
// for synchronization (from another thread). since this signal may block
|
||||
// or (worse) make another state change, the queue needs to unlock before
|
||||
// calling. thus, gstqueue.c::gst_queue_state_change() blocks, unblocks,
|
||||
// unlocks, then emits this.
|
||||
gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[STATE_CHANGE],
|
||||
GST_STATE (element));
|
||||
return TRUE;
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_element_shutdown (GtkObject *object)
|
||||
{
|
||||
GstElement *element = GST_ELEMENT (object);
|
||||
|
||||
GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "shutdown\n");
|
||||
|
||||
if (GST_IS_BIN (GST_OBJECT_PARENT (element)))
|
||||
gst_bin_remove (GST_BIN (GST_OBJECT_PARENT (element)), element);
|
||||
|
||||
if (GTK_OBJECT_CLASS (parent_class)->shutdown)
|
||||
GTK_OBJECT_CLASS (parent_class)->shutdown (object);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -775,16 +905,29 @@ gst_element_real_destroy (GtkObject *object)
|
|||
GList *pads;
|
||||
GstPad *pad;
|
||||
|
||||
// g_print("in gst_element_real_destroy()\n");
|
||||
GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "destroy\n");
|
||||
|
||||
pads = element->pads;
|
||||
if (element->pads) {
|
||||
GList *orig;
|
||||
orig = pads = g_list_copy (element->pads);
|
||||
while (pads) {
|
||||
pad = GST_PAD (pads->data);
|
||||
gst_pad_destroy (pad);
|
||||
//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;
|
||||
}
|
||||
|
||||
element->numsrcpads = 0;
|
||||
element->numsinkpads = 0;
|
||||
|
||||
if (GTK_OBJECT_CLASS (parent_class)->destroy)
|
||||
GTK_OBJECT_CLASS (parent_class)->destroy (object);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -830,7 +973,7 @@ gst_element_save_thyself (GstObject *object,
|
|||
|
||||
oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
|
||||
|
||||
xmlNewChild(parent, NULL, "name", gst_object_get_name (GST_OBJECT (element)));
|
||||
xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
|
||||
|
||||
if (oclass->elementfactory != NULL) {
|
||||
GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
|
||||
|
@ -839,6 +982,9 @@ gst_element_save_thyself (GstObject *object,
|
|||
xmlNewChild (parent, NULL, "version", factory->details->version);
|
||||
}
|
||||
|
||||
// if (element->manager)
|
||||
// xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager));
|
||||
|
||||
// output all args to the element
|
||||
type = GTK_OBJECT_TYPE (element);
|
||||
while (type != GTK_TYPE_INVALID) {
|
||||
|
@ -918,7 +1064,7 @@ gst_element_save_thyself (GstObject *object,
|
|||
}
|
||||
|
||||
/**
|
||||
* gst_element_load_thyself:
|
||||
* gst_element_restore_thyself:
|
||||
* @self: the xml node
|
||||
* @parent: the parent of this object when it's loaded
|
||||
*
|
||||
|
@ -927,7 +1073,7 @@ gst_element_save_thyself (GstObject *object,
|
|||
* Returns: the new element
|
||||
*/
|
||||
GstElement*
|
||||
gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
|
||||
gst_element_restore_thyself (xmlNodePtr self, GstObject *parent)
|
||||
{
|
||||
xmlNodePtr children = self->xmlChildrenNode;
|
||||
GstElement *element;
|
||||
|
@ -948,7 +1094,7 @@ gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
|
|||
g_return_val_if_fail (name != NULL, NULL);
|
||||
g_return_val_if_fail (type != NULL, NULL);
|
||||
|
||||
GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"\n", name, type);
|
||||
GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"", name, type);
|
||||
|
||||
element = gst_elementfactory_make (type, name);
|
||||
|
||||
|
@ -1002,32 +1148,33 @@ gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
|
|||
}
|
||||
|
||||
/**
|
||||
* gst_element_set_manager:
|
||||
* gst_element_set_sched:
|
||||
* @element: Element to set manager of.
|
||||
* @manager: Element to be the manager.
|
||||
* @sched: @GstSchedule to set.
|
||||
*
|
||||
* Sets the manager of the element. For internal use only, unless you're
|
||||
* Sets the scheduler of the element. For internal use only, unless you're
|
||||
* writing a new bin subclass.
|
||||
*/
|
||||
void
|
||||
gst_element_set_manager (GstElement *element,
|
||||
GstElement *manager)
|
||||
gst_element_set_sched (GstElement *element,
|
||||
GstSchedule *sched)
|
||||
{
|
||||
element->manager = manager;
|
||||
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p",sched);
|
||||
element->sched = sched;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_element_get_manager:
|
||||
* gst_element_get_sched:
|
||||
* @element: Element to get manager of.
|
||||
*
|
||||
* Returns the manager of the element.
|
||||
* Returns the scheduler of the element.
|
||||
*
|
||||
* Returns: Element's manager
|
||||
* Returns: Element's scheduler
|
||||
*/
|
||||
GstElement*
|
||||
gst_element_get_manager (GstElement *element)
|
||||
GstSchedule*
|
||||
gst_element_get_sched (GstElement *element)
|
||||
{
|
||||
return element->manager;
|
||||
return element->sched;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1070,3 +1217,24 @@ gst_element_signal_eos (GstElement *element)
|
|||
GST_FLAG_SET(element,GST_ELEMENT_COTHREAD_STOPPING);
|
||||
}
|
||||
|
||||
|
||||
const gchar *gst_element_statename(int state) {
|
||||
switch (state) {
|
||||
#ifdef GST_DEBUG_COLOR
|
||||
case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
|
||||
case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
|
||||
case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
|
||||
case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
|
||||
case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
|
||||
default: return "\033[01;37;41mUNKNOWN!\033[00m";
|
||||
#else
|
||||
case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
|
||||
case GST_STATE_NULL: return "NULL";break;
|
||||
case GST_STATE_READY: return "READY";break;
|
||||
case GST_STATE_PLAYING: return "PLAYING";break;
|
||||
case GST_STATE_PAUSED: return "PAUSED";break;
|
||||
default: return "UNKNOWN!";
|
||||
#endif
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -46,8 +46,8 @@ typedef enum {
|
|||
GST_STATE_NONE_PENDING = 0,
|
||||
GST_STATE_NULL = (1 << 0),
|
||||
GST_STATE_READY = (1 << 1),
|
||||
GST_STATE_PLAYING = (1 << 2),
|
||||
GST_STATE_PAUSED = (1 << 3),
|
||||
GST_STATE_PAUSED = (1 << 2),
|
||||
GST_STATE_PLAYING = (1 << 3),
|
||||
} GstElementState;
|
||||
|
||||
typedef enum {
|
||||
|
@ -56,28 +56,19 @@ typedef enum {
|
|||
GST_STATE_ASYNC = 2,
|
||||
} GstElementStateReturn;
|
||||
|
||||
static inline char *_gst_print_statename(int state) {
|
||||
switch (state) {
|
||||
case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
|
||||
case GST_STATE_NULL: return "NULL";break;
|
||||
case GST_STATE_READY: return "READY";break;
|
||||
case GST_STATE_PLAYING: return "PLAYING";break;
|
||||
case GST_STATE_PAUSED: return "PAUSED";break;
|
||||
default: return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// NOTE: this probably should be done with an #ifdef to decide whether to safe-cast
|
||||
// or to just do the non-checking cast.
|
||||
#define GST_STATE(obj) (GST_ELEMENT(obj)->current_state)
|
||||
#define GST_STATE_PENDING(obj) (GST_ELEMENT(obj)->pending_state)
|
||||
|
||||
// Note: using 8 bit shift mostly "just because", it leaves us enough room to grow <g>
|
||||
#define GST_STATE_TRANSITION(obj) ((GST_STATE(obj)<<8) | GST_STATE_PENDING(obj))
|
||||
#define GST_STATE_NULL_TO_READY ((GST_STATE_NULL<<8) | GST_STATE_READY)
|
||||
#define GST_STATE_READY_TO_PLAYING ((GST_STATE_READY<<8) | GST_STATE_PLAYING)
|
||||
#define GST_STATE_PLAYING_TO_PAUSED ((GST_STATE_PLAYING<<8) | GST_STATE_PAUSED)
|
||||
#define GST_STATE_READY_TO_PAUSED ((GST_STATE_READY<<8) | GST_STATE_PAUSED)
|
||||
#define GST_STATE_PAUSED_TO_PLAYING ((GST_STATE_PAUSED<<8) | GST_STATE_PLAYING)
|
||||
#define GST_STATE_PLAYING_TO_READY ((GST_STATE_PLAYING<<8) | GST_STATE_READY)
|
||||
#define GST_STATE_PLAYING_TO_PAUSED ((GST_STATE_PLAYING<<8) | GST_STATE_PAUSED)
|
||||
#define GST_STATE_PAUSED_TO_READY ((GST_STATE_PAUSED<<8) | GST_STATE_READY)
|
||||
#define GST_STATE_READY_TO_NULL ((GST_STATE_READY<<8) | GST_STATE_NULL)
|
||||
|
||||
#define GST_TYPE_ELEMENT \
|
||||
|
@ -104,6 +95,9 @@ typedef enum {
|
|||
|
||||
/***** !!!!! need to have a flag that says that an element must
|
||||
*not* be an entry into a scheduling chain !!!!! *****/
|
||||
/* this element for some reason doesn't obey COTHREAD_STOPPING, or
|
||||
has some other reason why it can't be the entry */
|
||||
GST_ELEMENT_NO_ENTRY,
|
||||
|
||||
/* there is a new loopfunction ready for placement */
|
||||
GST_ELEMENT_NEW_LOOPFUNC,
|
||||
|
@ -116,7 +110,7 @@ typedef enum {
|
|||
GST_ELEMENT_EOS,
|
||||
|
||||
/* use some padding for future expansion */
|
||||
GST_ELEMENT_FLAG_LAST = GST_OBJECT_FLAG_LAST + 8,
|
||||
GST_ELEMENT_FLAG_LAST = GST_OBJECT_FLAG_LAST + 12,
|
||||
} GstElementFlags;
|
||||
|
||||
#define GST_ELEMENT_IS_THREAD_SUGGESTED(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_THREAD_SUGGESTED))
|
||||
|
@ -125,10 +119,12 @@ typedef enum {
|
|||
|
||||
#define GST_ELEMENT_NAME(obj) (GST_OBJECT_NAME(obj))
|
||||
#define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj))
|
||||
#define GST_ELEMENT_MANAGER(obj) (((GstElement*)(obj))->manager)
|
||||
#define GST_ELEMENT_SCHED(obj) (((GstElement*)(obj))->sched)
|
||||
#define GST_ELEMENT_PADS(obj) ((obj)->pads)
|
||||
|
||||
typedef struct _GstElement GstElement;
|
||||
typedef struct _GstElementClass GstElementClass;
|
||||
//typedef struct _GstElement GstElement;
|
||||
//typedef struct _GstElementClass GstElementClass;
|
||||
typedef struct _GstElementDetails GstElementDetails;
|
||||
typedef struct _GstElementFactory GstElementFactory;
|
||||
|
||||
|
@ -149,6 +145,7 @@ struct _GstElement {
|
|||
GList *pads;
|
||||
|
||||
GstElement *manager;
|
||||
GstSchedule *sched;
|
||||
};
|
||||
|
||||
struct _GstElementClass {
|
||||
|
@ -160,10 +157,20 @@ struct _GstElementClass {
|
|||
/* signal callbacks */
|
||||
void (*state_change) (GstElement *element,GstElementState state);
|
||||
void (*new_pad) (GstElement *element,GstPad *pad);
|
||||
void (*pad_removed) (GstElement *element,GstPad *pad);
|
||||
void (*new_ghost_pad) (GstElement *element,GstPad *pad);
|
||||
void (*ghost_pad_removed) (GstElement *element,GstPad *pad);
|
||||
void (*error) (GstElement *element,gchar *error);
|
||||
void (*eos) (GstElement *element);
|
||||
|
||||
/* local pointers for get/set */
|
||||
void (*set_arg) (GtkObject *object,
|
||||
GtkArg *arg,
|
||||
guint arg_id);
|
||||
void (*get_arg) (GtkObject *object,
|
||||
GtkArg *arg,
|
||||
guint arg_id);
|
||||
|
||||
/* change the element state */
|
||||
GstElementStateReturn (*change_state) (GstElement *element);
|
||||
/* request a new pad */
|
||||
|
@ -202,10 +209,11 @@ const gchar* gst_element_get_name (GstElement *element);
|
|||
void gst_element_set_parent (GstElement *element, GstObject *parent);
|
||||
GstObject* gst_element_get_parent (GstElement *element);
|
||||
|
||||
void gst_element_set_manager (GstElement *element, GstElement *manager);
|
||||
GstElement* gst_element_get_manager (GstElement *element);
|
||||
void gst_element_set_sched (GstElement *element, GstSchedule *sched);
|
||||
GstSchedule* gst_element_get_sched (GstElement *element);
|
||||
|
||||
void gst_element_add_pad (GstElement *element, GstPad *pad);
|
||||
void gst_element_remove_pad (GstElement *element, GstPad *pad);
|
||||
GstPad* gst_element_get_pad (GstElement *element, const gchar *name);
|
||||
GList* gst_element_get_pad_list (GstElement *element);
|
||||
GList* gst_element_get_padtemplate_list (GstElement *element);
|
||||
|
@ -232,7 +240,7 @@ void gst_element_error (GstElement *element, const gchar *error);
|
|||
GstElementFactory* gst_element_get_factory (GstElement *element);
|
||||
|
||||
/* XML write and read */
|
||||
GstElement* gst_element_load_thyself (xmlNodePtr self, GstObject *parent);
|
||||
GstElement* gst_element_restore_thyself (xmlNodePtr self, GstObject *parent);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -264,9 +272,13 @@ GstElement* gst_elementfactory_create (GstElementFactory *factory,
|
|||
/* FIXME this name is wrong, probably so is the one above it */
|
||||
GstElement* gst_elementfactory_make (const gchar *factoryname, const gchar *name);
|
||||
|
||||
|
||||
xmlNodePtr gst_elementfactory_save_thyself (GstElementFactory *factory, xmlNodePtr parent);
|
||||
GstElementFactory* gst_elementfactory_load_thyself (xmlNodePtr parent);
|
||||
|
||||
|
||||
const gchar * gst_element_statename (int state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -68,8 +68,6 @@ gst_elementfactory_find (const gchar *name)
|
|||
|
||||
g_return_val_if_fail(name != NULL, NULL);
|
||||
|
||||
GST_DEBUG (0,"gstelementfactory: find \"%s\"\n", name);
|
||||
|
||||
walk = _gst_elementfactories;
|
||||
while (walk) {
|
||||
factory = (GstElementFactory *)(walk->data);
|
||||
|
@ -78,6 +76,8 @@ gst_elementfactory_find (const gchar *name)
|
|||
walk = g_list_next(walk);
|
||||
}
|
||||
|
||||
// this should be an ERROR
|
||||
GST_DEBUG (GST_CAT_ELEMENTFACTORY,"no such elementfactoryfactory \"%s\"\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,8 @@ gst_elementfactory_create (GstElementFactory *factory,
|
|||
g_return_val_if_fail(factory != NULL, NULL);
|
||||
g_return_val_if_fail(name != NULL, NULL);
|
||||
|
||||
GST_DEBUG (0,"gstelementfactory: create \"%s\" \"%s\"\n", factory->name, name);
|
||||
GST_DEBUG (GST_CAT_ELEMENTFACTORY,"creating element from factory \"%s\" with name \"%s\"\n",
|
||||
factory->name, name);
|
||||
|
||||
// it's not loaded, try to load the plugin
|
||||
if (factory->type == 0) {
|
||||
|
@ -160,12 +161,11 @@ gst_elementfactory_create (GstElementFactory *factory,
|
|||
// create an instance of the element
|
||||
element = GST_ELEMENT(gtk_type_new(factory->type));
|
||||
g_assert(element != NULL);
|
||||
gst_object_ref(GST_OBJECT(element));
|
||||
|
||||
// attempt to set the elemenfactory class pointer if necessary
|
||||
oclass = GST_ELEMENT_CLASS(GTK_OBJECT(element)->klass);
|
||||
if (oclass->elementfactory == NULL) {
|
||||
GST_DEBUG (0,"gstelementfactory: class %s\n", factory->name);
|
||||
GST_DEBUG (GST_CAT_ELEMENTFACTORY,"class %s\n", factory->name);
|
||||
oclass->elementfactory = factory;
|
||||
}
|
||||
|
||||
|
@ -194,7 +194,7 @@ gst_elementfactory_make (const gchar *factoryname, const gchar *name)
|
|||
g_return_val_if_fail(factoryname != NULL, NULL);
|
||||
g_return_val_if_fail(name != NULL, NULL);
|
||||
|
||||
GST_DEBUG (0,"gstelementfactory: make \"%s\" \"%s\"\n", factoryname, name);
|
||||
// GST_DEBUG (GST_CAT_ELEMENTFACTORY,"gstelementfactory: make \"%s\" \"%s\"\n", factoryname, name);
|
||||
|
||||
//gst_plugin_load_elementfactory(factoryname);
|
||||
factory = gst_elementfactory_find(factoryname);
|
||||
|
|
316
gst/gstinfo.c
316
gst/gstinfo.c
|
@ -20,6 +20,7 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "gst_private.h"
|
||||
#include "gstelement.h"
|
||||
#include "gstpad.h"
|
||||
|
@ -27,19 +28,7 @@
|
|||
extern gchar *_gst_progname;
|
||||
|
||||
|
||||
/***** DEBUG system *****/
|
||||
GHashTable *__gst_function_pointers = NULL;
|
||||
|
||||
|
||||
|
||||
/***** INFO system *****/
|
||||
GstInfoHandler _gst_info_handler = gst_default_info_handler;
|
||||
#ifdef GST_INFO_ENABLED_VERBOSE
|
||||
guint32 _gst_info_categories = 0xffffffff;
|
||||
#else
|
||||
guint32 _gst_info_categories = 0x00000001;
|
||||
#endif
|
||||
|
||||
/***** Categories and colorization *****/
|
||||
static gchar *_gst_info_category_strings[] = {
|
||||
"GST_INIT",
|
||||
"COTHREADS",
|
||||
|
@ -48,9 +37,9 @@ static gchar *_gst_info_category_strings[] = {
|
|||
"AUTOPLUG_ATTEMPT",
|
||||
"PARENTAGE",
|
||||
"STATES",
|
||||
"PLANING",
|
||||
"PLANNING",
|
||||
"SCHEDULING",
|
||||
"OPERATION",
|
||||
"DATAFLOW",
|
||||
"BUFFER",
|
||||
"CAPS",
|
||||
"CLOCK",
|
||||
|
@ -66,48 +55,195 @@ static gchar *_gst_info_category_strings[] = {
|
|||
"TYPES",
|
||||
"XML",
|
||||
"NEGOTIATION",
|
||||
"REFCOUNTING",
|
||||
};
|
||||
|
||||
const gchar *_gst_category_colors[] = {
|
||||
[GST_CAT_GST_INIT] = "00;37",
|
||||
/**
|
||||
* gst_get_category_name:
|
||||
* @category: the category to return the name of
|
||||
*
|
||||
* Returns: string containing the name of the category
|
||||
*/
|
||||
const gchar *
|
||||
gst_get_category_name (gint category) {
|
||||
if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
|
||||
return _gst_info_category_strings[category];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Attribute codes:
|
||||
* 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
|
||||
* Text color codes:
|
||||
* 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
|
||||
* Background color codes:
|
||||
* 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
|
||||
*/
|
||||
const gchar *_gst_category_colors[32] = {
|
||||
[GST_CAT_GST_INIT] = "07;37",
|
||||
[GST_CAT_COTHREADS] = "00;32",
|
||||
[GST_CAT_COTHREAD_SWITCH] = "00;32",
|
||||
[GST_CAT_COTHREAD_SWITCH] = "00;37;42",
|
||||
[GST_CAT_AUTOPLUG] = "00;34",
|
||||
[GST_CAT_AUTOPLUG_ATTEMPT] = "00;34",
|
||||
[GST_CAT_PARENTAGE] = "",
|
||||
[GST_CAT_AUTOPLUG_ATTEMPT] = "00;36;44",
|
||||
[GST_CAT_PARENTAGE] = "01;37;41", // !!
|
||||
[GST_CAT_STATES] = "00;31",
|
||||
[GST_CAT_PLANNING] = "00;35",
|
||||
[GST_CAT_PLANNING] = "07;35",
|
||||
[GST_CAT_SCHEDULING] = "00;35",
|
||||
[GST_CAT_DATAFLOW] = "00;32",
|
||||
[GST_CAT_BUFFER] = "00;32",
|
||||
[GST_CAT_CAPS] = "",
|
||||
[GST_CAT_CLOCK] = "",
|
||||
[GST_CAT_ELEMENT_PADS] = "",
|
||||
[GST_CAT_ELEMENTFACTORY] = "",
|
||||
[GST_CAT_PADS] = "",
|
||||
[GST_CAT_PIPELINE] = "",
|
||||
[GST_CAT_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] = "",
|
||||
[GST_CAT_PROPERTIES] = "00;37;44", // !!
|
||||
[GST_CAT_THREAD] = "00;31",
|
||||
[GST_CAT_TYPES] = "",
|
||||
[GST_CAT_XML] = "",
|
||||
[GST_CAT_NEGOTIATION] = "",
|
||||
[GST_CAT_TYPES] = "01;37;41", // !!
|
||||
[GST_CAT_XML] = "01;37;41", // !!
|
||||
[GST_CAT_NEGOTIATION] = "07;34",
|
||||
[GST_CAT_REFCOUNTING] = "00;34:42",
|
||||
|
||||
[31] = "",
|
||||
};
|
||||
|
||||
|
||||
/* colorization hash */
|
||||
/* colorization hash - DEPRACATED in favor of above */
|
||||
inline gint _gst_debug_stringhash_color(gchar *file) {
|
||||
int filecolor;
|
||||
int filecolor = 0;
|
||||
while (file[0]) filecolor += *(char *)(file++);
|
||||
filecolor = (filecolor % 6) + 31;
|
||||
return filecolor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***** DEBUG system *****/
|
||||
GstDebugHandler _gst_debug_handler = gst_default_debug_handler;
|
||||
guint32 _gst_debug_categories = 0x00000000;
|
||||
|
||||
/**
|
||||
* gst_default_debug_handler:
|
||||
* @category: category of the DEBUG message
|
||||
* @file: the file the DEBUG occurs in
|
||||
* @function: the function the DEBUG occurs in
|
||||
* @line: the line number in the file
|
||||
* @debug_string: the current debug_string in the function, if any
|
||||
* @element: pointer to the #GstElement in question
|
||||
* @string: the actual DEBUG string
|
||||
*
|
||||
* Prints out the DEBUG mesage in a variant of the following form:
|
||||
*
|
||||
* DEBUG(pid:cid):gst_function:542(args): [elementname] something neat happened
|
||||
*/
|
||||
void
|
||||
gst_default_debug_handler (gint category, gboolean incore, gchar *file, gchar *function,
|
||||
gint line, gchar *debug_string,
|
||||
void *element, gchar *string)
|
||||
{
|
||||
gchar *empty = "";
|
||||
gchar *elementname = empty,*location = empty;
|
||||
int pthread_id = getpid();
|
||||
int cothread_id = cothread_getcurrent();
|
||||
#ifdef GST_DEBUG_COLOR
|
||||
int pthread_color = pthread_id%6 + 31;
|
||||
int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
|
||||
#endif
|
||||
|
||||
if (debug_string == NULL) debug_string = "";
|
||||
// if (category != GST_CAT_GST_INIT)
|
||||
location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
|
||||
if (element && GST_IS_ELEMENT (element))
|
||||
#ifdef GST_DEBUG_COLOR
|
||||
elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
|
||||
#else
|
||||
elementname = g_strdup_printf (" [%s]", GST_OBJECT_NAME (element));
|
||||
#endif
|
||||
|
||||
#ifdef GST_DEBUG_COLOR
|
||||
fprintf(stderr,"DEBUG(\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
|
||||
"%s;%sm%s%s\033[00m %s",
|
||||
pthread_color,pthread_id,cothread_color,cothread_id,incore?"00":"01",
|
||||
_gst_category_colors[category],location,elementname,string);
|
||||
#else
|
||||
fprintf(stderr,"DEBUG(%5d:%2d)%s%s %s",
|
||||
pthread_id,cothread_id,location,elementname,string);
|
||||
#endif /* GST_DEBUG_COLOR */
|
||||
|
||||
if (location != empty) g_free(location);
|
||||
if (elementname != empty) g_free(elementname);
|
||||
|
||||
g_free(string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_debug_set_categories:
|
||||
* @categories: bitmask of DEBUG categories to enable
|
||||
*
|
||||
* Enable the output of DEBUG categories based on the given bitmask.
|
||||
* The bit for any given category is (1 << GST_CAT_...).
|
||||
*/
|
||||
void
|
||||
gst_debug_set_categories (guint32 categories) {
|
||||
_gst_debug_categories = categories;
|
||||
if (categories)
|
||||
GST_INFO (0, "setting DEBUG categories to 0x%08X",categories);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_get_categories:
|
||||
*
|
||||
* Returns: the current bitmask of enabled DEBUG categories
|
||||
* The bit for any given category is (1 << GST_CAT_...).
|
||||
*/
|
||||
guint32
|
||||
gst_debug_get_categories () {
|
||||
return _gst_debug_categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_enable_category:
|
||||
* @category: the category to enable
|
||||
*
|
||||
* Enables the given GST_CAT_... DEBUG category.
|
||||
*/
|
||||
void
|
||||
gst_debug_enable_category (gint category) {
|
||||
_gst_debug_categories |= (1 << category);
|
||||
if (_gst_debug_categories)
|
||||
GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_disable_category:
|
||||
* @category: the category to disable
|
||||
*
|
||||
* Disables the given GST_CAT_... DEBUG category.
|
||||
*/
|
||||
void
|
||||
gst_debug_disable_category (gint category) {
|
||||
_gst_debug_categories &= ~ (1 << category);
|
||||
if (_gst_debug_categories)
|
||||
GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***** INFO system *****/
|
||||
GstInfoHandler _gst_info_handler = gst_default_info_handler;
|
||||
#ifdef GST_INFO_ENABLED_VERBOSE
|
||||
guint32 _gst_info_categories = 0xffffffff;
|
||||
#else
|
||||
guint32 _gst_info_categories = 0x00000001;
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* gst_default_info_handler:
|
||||
* @category: category of the INFO message
|
||||
|
@ -123,12 +259,18 @@ inline gint _gst_debug_stringhash_color(gchar *file) {
|
|||
* INFO:gst_function:542(args): [elementname] something neat happened
|
||||
*/
|
||||
void
|
||||
gst_default_info_handler (gint category, gchar *file, gchar *function,
|
||||
gst_default_info_handler (gint category, gboolean incore,gchar *file, gchar *function,
|
||||
gint line, gchar *debug_string,
|
||||
void *element, gchar *string)
|
||||
{
|
||||
gchar *empty = "";
|
||||
gchar *elementname = empty,*location = empty;
|
||||
int pthread_id = getpid();
|
||||
int cothread_id = cothread_getcurrent();
|
||||
#ifdef GST_DEBUG_COLOR
|
||||
int pthread_color = pthread_id%6 + 31;
|
||||
int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
|
||||
#endif
|
||||
|
||||
if (debug_string == NULL) debug_string = "";
|
||||
if (category != GST_CAT_GST_INIT)
|
||||
|
@ -138,15 +280,17 @@ gst_default_info_handler (gint category, gchar *file, gchar *function,
|
|||
|
||||
#ifdef GST_DEBUG_ENABLED
|
||||
#ifdef GST_DEBUG_COLOR
|
||||
fprintf(stderr,"INFO(%d:%d):\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
|
||||
getpid(),cothread_getcurrent(),_gst_category_colors[category],location,elementname,string);
|
||||
fprintf(stderr,"\033[01mINFO\033[00m (\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
|
||||
GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
|
||||
pthread_color,pthread_id,cothread_color,cothread_id,
|
||||
_gst_category_colors[category],location,elementname,string);
|
||||
#else
|
||||
fprintf(stderr,"INFO(%d:%d):%s%s %s\n",
|
||||
getpid(),cothread_getcurrent(),location,elementname,string);
|
||||
fprintf(stderr,"INFO (%5d:%2d)%s%s %s\n",
|
||||
pthread_id,cothread_id,location,elementname,string);
|
||||
#endif /* GST_DEBUG_COLOR */
|
||||
#else
|
||||
#ifdef GST_DEBUG_COLOR
|
||||
fprintf(stderr,"INFO:\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
|
||||
fprintf(stderr,"\033[01mINFO\033[00m:\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
|
||||
location,elementname,_gst_category_colors[category],string);
|
||||
#else
|
||||
fprintf(stderr,"INFO:%s%s %s\n",
|
||||
|
@ -213,77 +357,6 @@ gst_info_disable_category (gint category) {
|
|||
|
||||
|
||||
|
||||
/***** DEBUG system *****/
|
||||
guint32 _gst_debug_categories = 0x00000000;
|
||||
|
||||
|
||||
/**
|
||||
* gst_debug_set_categories:
|
||||
* @categories: bitmask of DEBUG categories to enable
|
||||
*
|
||||
* Enable the output of DEBUG categories based on the given bitmask.
|
||||
* The bit for any given category is (1 << GST_CAT_...).
|
||||
*/
|
||||
void
|
||||
gst_debug_set_categories (guint32 categories) {
|
||||
_gst_debug_categories = categories;
|
||||
if (categories)
|
||||
GST_INFO (0, "setting DEBUG categories to 0x%08X",categories);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_get_categories:
|
||||
*
|
||||
* Returns: the current bitmask of enabled DEBUG categories
|
||||
* The bit for any given category is (1 << GST_CAT_...).
|
||||
*/
|
||||
guint32
|
||||
gst_debug_get_categories () {
|
||||
return _gst_debug_categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_enable_category:
|
||||
* @category: the category to enable
|
||||
*
|
||||
* Enables the given GST_CAT_... DEBUG category.
|
||||
*/
|
||||
void
|
||||
gst_debug_enable_category (gint category) {
|
||||
_gst_debug_categories |= (1 << category);
|
||||
if (_gst_debug_categories)
|
||||
GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_debug_disable_category:
|
||||
* @category: the category to disable
|
||||
*
|
||||
* Disables the given GST_CAT_... DEBUG category.
|
||||
*/
|
||||
void
|
||||
gst_debug_disable_category (gint category) {
|
||||
_gst_debug_categories &= ~ (1 << category);
|
||||
if (_gst_debug_categories)
|
||||
GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_get_category_name:
|
||||
* @category: the category to return the name of
|
||||
*
|
||||
* Returns: string containing the name of the category
|
||||
*/
|
||||
const gchar *
|
||||
gst_get_category_name (gint category) {
|
||||
if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
|
||||
return _gst_info_category_strings[category];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***** ERROR system *****/
|
||||
GstErrorHandler _gst_error_handler = gst_default_error_handler;
|
||||
|
||||
|
@ -364,3 +437,24 @@ gst_default_error_handler (gchar *file, gchar *function,
|
|||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***** DEBUG system *****/
|
||||
GHashTable *__gst_function_pointers = NULL;
|
||||
|
||||
gchar *
|
||||
_gst_debug_nameof_funcptr (void *ptr)
|
||||
{
|
||||
gchar *ptrname;
|
||||
Dl_info dlinfo;
|
||||
if (__gst_function_pointers) {
|
||||
if ((ptrname = g_hash_table_lookup(__gst_function_pointers,ptr)))
|
||||
return g_strdup(ptrname);
|
||||
} else if (dladdr(ptr,&dlinfo) && dlinfo.dli_sname) {
|
||||
return g_strdup(dlinfo.dli_sname);
|
||||
} else {
|
||||
return g_strdup_printf("%p",ptr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
234
gst/gstinfo.h
234
gst/gstinfo.h
|
@ -34,6 +34,14 @@
|
|||
#include "cothreads.h"
|
||||
|
||||
|
||||
/***** are we in the core or not? *****/
|
||||
#ifdef __GST_PRIVATE_H__
|
||||
#define _GST_DEBUG_INCORE TRUE
|
||||
#else
|
||||
#define _GST_DEBUG_INCORE FALSE
|
||||
#endif
|
||||
|
||||
|
||||
/* colorization stuff */
|
||||
#ifdef GST_DEBUG_COLOR
|
||||
#ifdef __GST_PRIVATE_H__ /* FIXME this should be some libgst.la -specific thing */
|
||||
|
@ -47,13 +55,51 @@ gint _gst_debug_stringhash_color(gchar *file);
|
|||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* Categories
|
||||
**********************************************************************/
|
||||
|
||||
const gchar * gst_get_category_name (gint category);
|
||||
|
||||
enum {
|
||||
GST_CAT_GST_INIT = 0, // Library initialization
|
||||
GST_CAT_COTHREADS, // Cothread creation, etc.
|
||||
GST_CAT_COTHREAD_SWITCH, // Cothread switching
|
||||
GST_CAT_AUTOPLUG, // Successful autoplug results
|
||||
GST_CAT_AUTOPLUG_ATTEMPT, // Attempted autoplug operations
|
||||
GST_CAT_PARENTAGE, // GstBin parentage issues
|
||||
GST_CAT_STATES, // State changes and such
|
||||
GST_CAT_PLANNING, // Plan generation
|
||||
GST_CAT_SCHEDULING, // Schedule construction
|
||||
GST_CAT_DATAFLOW, // Events during actual data movement
|
||||
GST_CAT_BUFFER, // Buffer creation/destruction
|
||||
GST_CAT_CAPS, // Capabilities matching
|
||||
GST_CAT_CLOCK, // Clocking
|
||||
GST_CAT_ELEMENT_PADS, // Element pad management
|
||||
GST_CAT_ELEMENTFACTORY, // Elementfactory stuff
|
||||
GST_CAT_PADS, // Pad creation/connection
|
||||
GST_CAT_PIPELINE, // Pipeline stuff
|
||||
GST_CAT_PLUGIN_LOADING, // Plugin loading
|
||||
GST_CAT_PLUGIN_ERRORS, // Errors during plugin loading
|
||||
GST_CAT_PLUGIN_INFO, // Plugin state information
|
||||
GST_CAT_PROPERTIES, // Properties
|
||||
GST_CAT_THREAD, // Thread creation/management
|
||||
GST_CAT_TYPES, // Typing
|
||||
GST_CAT_XML, // XML load/save of everything
|
||||
GST_CAT_NEGOTIATION, // Caps Negotiation stuff
|
||||
GST_CAT_REFCOUNTING, // Ref Counting stuff
|
||||
|
||||
GST_CAT_MAX_CATEGORY = 31
|
||||
};
|
||||
|
||||
extern const gchar *_gst_category_colors[32];
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DEBUG system
|
||||
**********************************************************************/
|
||||
|
||||
extern guint32 _gst_debug_categories;
|
||||
|
||||
/* for include files that make too much noise normally */
|
||||
#ifdef GST_DEBUG_FORCE_DISABLE
|
||||
#undef GST_DEBUG_ENABLED
|
||||
|
@ -69,109 +115,69 @@ extern guint32 _gst_debug_categories;
|
|||
//#define GST_DEBUG_ENABLE_CATEGORIES 0x00000000
|
||||
//#endif
|
||||
|
||||
|
||||
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 */
|
||||
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
|
||||
#define GST_DEBUG(cat,format,args...) G_STMT_START{ \
|
||||
if (((1<<cat) & GST_DEBUG_ENABLE_CATEGORIES) && \
|
||||
((1<<cat) & _gst_debug_categories)) \
|
||||
(_debug_string != NULL) ? \
|
||||
fprintf(stderr,GST_DEBUG_PREFIX(cat,"%s: "format , _debug_string , ## args )) : \
|
||||
fprintf(stderr,GST_DEBUG_PREFIX(cat,": "format , ## args )); \
|
||||
if ((1<<cat) & _gst_debug_categories) \
|
||||
_gst_debug_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
|
||||
NULL,g_strdup_printf( format , ## args )); \
|
||||
}G_STMT_END
|
||||
|
||||
#define GST_DEBUG_NOPREFIX(cat,format,args...) G_STMT_START{ \
|
||||
if (((1<<cat) & GST_DEBUG_ENABLE_CATEGORIES) && \
|
||||
((1<<cat) & _gst_debug_categories)) \
|
||||
fprintf(stderr,format , ## args ); \
|
||||
#define GST_DEBUG_ELEMENT(cat,element,format,args...) G_STMT_START{ \
|
||||
if ((1<<cat) & _gst_debug_categories) \
|
||||
_gst_debug_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
|
||||
element,g_strdup_printf( format , ## args )); \
|
||||
}G_STMT_END
|
||||
|
||||
#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
|
||||
#define GST_DEBUG(format, args...)
|
||||
#define GST_DEBUG_NOPREFIX(format, args...)
|
||||
#define GST_DEBUG_ENTER(format, args...)
|
||||
#define GST_DEBUG_LEAVE(format, args...)
|
||||
#define GST_DEBUG_SET_STRING(format, args...)
|
||||
#define GST_DEBUG_ENTER_STRING
|
||||
#define GST_DEBUG(cat,format,args...)
|
||||
#define GST_DEBUG_ELEMENT(cat,element,format,args...)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/********** some convenience macros for debugging **********/
|
||||
#define GST_DEBUG_PAD_NAME(pad) \
|
||||
(GST_OBJECT_PARENT(pad) != NULL) ? \
|
||||
GST_OBJECT_NAME (GST_OBJECT_PARENT(pad)) : \
|
||||
"''", GST_OBJECT_NAME (pad)
|
||||
|
||||
|
||||
|
||||
/********** function pointer stuff **********/
|
||||
extern GHashTable *__gst_function_pointers;
|
||||
|
||||
#ifdef GST_DEBUG_ENABLED
|
||||
#define GST_DEBUG_FUNCPTR(ptr) _gst_debug_register_funcptr((void *)(ptr), #ptr)
|
||||
#define GST_DEBUG_FUNCPTR_NAME(ptr) _gst_debug_nameof_funcptr((void *)ptr)
|
||||
#ifdef GST_DEBUG_COLOR
|
||||
#define GST_DEBUG_ENTER(format, args...) GST_DEBUG( 31 , format ": \033[01;37mentering\033[00m\n" , ##args )
|
||||
#define GST_DEBUG_LEAVE(format, args...) GST_DEBUG( 31 , format ": \033[01;37mleaving\033[00m\n" , ##args )
|
||||
#else
|
||||
#define GST_DEBUG_FUNCPTR(ptr) (ptr)
|
||||
#define GST_DEBUG_FUNCPTR_NAME(ptr) ""
|
||||
#define GST_DEBUG_ENTER(format, args...) GST_DEBUG( 31 , format ": entering\n" , ##args )
|
||||
#define GST_DEBUG_LEAVE(format, args...) GST_DEBUG( 31 , format ": leaving\n" , ##args )
|
||||
#endif
|
||||
|
||||
static inline void *
|
||||
_gst_debug_register_funcptr (void *ptr, gchar *ptrname)
|
||||
{
|
||||
if (!__gst_function_pointers) __gst_function_pointers = g_hash_table_new(g_direct_hash,g_direct_equal);
|
||||
if (!g_hash_table_lookup(__gst_function_pointers,ptr))
|
||||
g_hash_table_insert(__gst_function_pointers,ptr,ptrname);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline gchar *
|
||||
_gst_debug_nameof_funcptr (void *ptr)
|
||||
{
|
||||
gchar *ptrname = (gchar*)( __gst_function_pointers ? g_hash_table_lookup(__gst_function_pointers,ptr) : NULL );
|
||||
// FIXME this must go away, it's a major leak
|
||||
if (!ptrname) return g_strdup_printf("%p",ptr);
|
||||
else return ptrname;
|
||||
}
|
||||
/***** Colorized debug for thread ids *****/
|
||||
#ifdef GST_DEBUG_COLOR
|
||||
#define GST_DEBUG_THREAD_FORMAT "\033[00;%dm%d\033[00m"
|
||||
#define GST_DEBUG_THREAD_ARGS(id) ( ((id) < 0) ? 37 : ((id) % 6 + 31) ), (id)
|
||||
#else
|
||||
#define GST_DEBUG_THREAD_FORMAT "%d"
|
||||
#define GST_DEBUG_THREAD_ARGS(id) (id)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
|
@ -227,11 +233,11 @@ G_GNUC_UNUSED static GModule *_debug_self_module = NULL;
|
|||
* INFO system
|
||||
**********************************************************************/
|
||||
|
||||
typedef void (*GstInfoHandler) (gint category,gchar *file,gchar *function,
|
||||
typedef void (*GstInfoHandler) (gint category,gboolean incore,gchar *file,gchar *function,
|
||||
gint line,gchar *debug_string,
|
||||
void *element,gchar *string);
|
||||
|
||||
void gst_default_info_handler (gint category,gchar *file,gchar *function,
|
||||
void gst_default_info_handler (gint category,gboolean incore,gchar *file,gchar *function,
|
||||
gint line,gchar *debug_string,
|
||||
void *element,gchar *string);
|
||||
|
||||
|
@ -250,13 +256,13 @@ extern guint32 _gst_info_categories;
|
|||
#ifdef GST_INFO_ENABLED
|
||||
#define GST_INFO(cat,format,args...) G_STMT_START{ \
|
||||
if ((1<<cat) & _gst_info_categories) \
|
||||
_gst_info_handler(cat,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
|
||||
_gst_info_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
|
||||
NULL,g_strdup_printf( format , ## args )); \
|
||||
}G_STMT_END
|
||||
|
||||
#define GST_INFO_ELEMENT(cat,element,format,args...) G_STMT_START{ \
|
||||
if ((1<<cat) & _gst_info_categories) \
|
||||
_gst_info_handler(cat,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
|
||||
_gst_info_handler(cat,_GST_DEBUG_INCORE,__FILE__,__PRETTY_FUNCTION__,__LINE__,_debug_string, \
|
||||
element,g_strdup_printf( format , ## args )); \
|
||||
}G_STMT_END
|
||||
|
||||
|
@ -276,42 +282,6 @@ guint32 gst_debug_get_categories (void);
|
|||
void gst_debug_enable_category (gint category);
|
||||
void gst_debug_disable_category (gint category);
|
||||
|
||||
const gchar * gst_get_category_name (gint category);
|
||||
|
||||
|
||||
enum {
|
||||
GST_CAT_GST_INIT = 0, // Library initialization
|
||||
GST_CAT_COTHREADS, // Cothread creation, etc.
|
||||
GST_CAT_COTHREAD_SWITCH, // Cothread switching
|
||||
GST_CAT_AUTOPLUG, // Successful autoplug results
|
||||
GST_CAT_AUTOPLUG_ATTEMPT, // Attempted autoplug operations
|
||||
GST_CAT_PARENTAGE, // GstBin parentage issues
|
||||
GST_CAT_STATES, // State changes and such
|
||||
GST_CAT_PLANNING, // Plan generation
|
||||
GST_CAT_SCHEDULING, // Schedule construction
|
||||
GST_CAT_DATAFLOW, // Events during actual data movement
|
||||
GST_CAT_BUFFER, // Buffer creation/destruction
|
||||
GST_CAT_CAPS, // Capabilities matching
|
||||
GST_CAT_CLOCK, // Clocking
|
||||
GST_CAT_ELEMENT_PADS, // Element pad management
|
||||
GST_CAT_ELEMENTFACTORY, // Elementfactory stuff
|
||||
GST_CAT_PADS, // Pad creation/connection
|
||||
GST_CAT_PIPELINE, // Pipeline stuff
|
||||
GST_CAT_PLUGIN_LOADING, // Plugin loading
|
||||
GST_CAT_PLUGIN_ERRORS, // Errors during plugin loading
|
||||
GST_CAT_PLUGIN_INFO, // Plugin state information
|
||||
GST_CAT_PROPERTIES, // Properties
|
||||
GST_CAT_THREAD, // Thread creation/management
|
||||
GST_CAT_TYPES, // Typing
|
||||
GST_CAT_XML, // XML load/save of everything
|
||||
GST_CAT_NEGOTIATION, // Caps Negotiation stuff
|
||||
|
||||
GST_CAT_MAX_CATEGORY,
|
||||
};
|
||||
|
||||
|
||||
extern const gchar *_gst_category_colors[GST_CAT_MAX_CATEGORY];
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -339,4 +309,30 @@ extern GstErrorHandler _gst_error_handler;
|
|||
|
||||
|
||||
|
||||
|
||||
/********** function pointer stuff **********/
|
||||
extern GHashTable *__gst_function_pointers;
|
||||
|
||||
|
||||
#if GST_DEBUG_ENABLED
|
||||
#define GST_DEBUG_FUNCPTR(ptr) _gst_debug_register_funcptr((void *)(ptr), #ptr)
|
||||
#define GST_DEBUG_FUNCPTR_NAME(ptr) _gst_debug_nameof_funcptr((void *)ptr)
|
||||
#else
|
||||
#define GST_DEBUG_FUNCPTR(ptr) (ptr)
|
||||
#define GST_DEBUG_FUNCPTR_NAME(ptr) ""
|
||||
#endif
|
||||
|
||||
static inline void *
|
||||
_gst_debug_register_funcptr (void *ptr, gchar *ptrname)
|
||||
{
|
||||
if (!__gst_function_pointers) __gst_function_pointers = g_hash_table_new(g_direct_hash,g_direct_equal);
|
||||
if (!g_hash_table_lookup(__gst_function_pointers,ptr))
|
||||
g_hash_table_insert(__gst_function_pointers,ptr,ptrname);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
gchar *_gst_debug_nameof_funcptr (void *ptr);
|
||||
|
||||
|
||||
|
||||
#endif /* __GSTINFO_H__ */
|
||||
|
|
165
gst/gstobject.c
165
gst/gstobject.c
|
@ -53,6 +53,10 @@ static guint gst_signal_object_signals[SO_LAST_SIGNAL] = { 0 };
|
|||
static void gst_object_class_init (GstObjectClass *klass);
|
||||
static void gst_object_init (GstObject *object);
|
||||
|
||||
static void gst_object_real_destroy (GtkObject *gtk_object);
|
||||
static void gst_object_shutdown (GtkObject *gtk_object);
|
||||
static void gst_object_finalize (GtkObject *gtk_object);
|
||||
|
||||
static GtkObjectClass *parent_class = NULL;
|
||||
static guint gst_object_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
@ -105,6 +109,10 @@ gst_object_class_init (GstObjectClass *klass)
|
|||
|
||||
klass->path_string_separator = "/";
|
||||
klass->signal_object = gtk_type_new (gst_signal_object_get_type ());
|
||||
|
||||
gtkobject_class->shutdown = gst_object_shutdown;
|
||||
gtkobject_class->destroy = gst_object_real_destroy;
|
||||
gtkobject_class->finalize = gst_object_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -118,9 +126,12 @@ gst_object_init (GstObject *object)
|
|||
#ifdef HAVE_ATOMIC_H
|
||||
atomic_set(&(object->refcount),1);
|
||||
#else
|
||||
object->refcount++;
|
||||
object->refcount = 1;
|
||||
#endif
|
||||
object->parent = NULL;
|
||||
|
||||
object->flags = 0;
|
||||
GST_FLAG_SET (object, GST_FLOATING);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,6 +147,122 @@ gst_object_new (void)
|
|||
return GST_OBJECT (gtk_type_new (gst_object_get_type ()));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_object_ref:
|
||||
* @object: GstObject to reference
|
||||
*
|
||||
* Increments the refence count on the object.
|
||||
*/
|
||||
GstObject*
|
||||
gst_object_ref (GstObject *object)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
|
||||
|
||||
GST_DEBUG (GST_CAT_REFCOUNTING, "ref '%s' %d->%d\n",GST_OBJECT_NAME(object),
|
||||
GTK_OBJECT(object)->ref_count,GTK_OBJECT(object)->ref_count+1);
|
||||
|
||||
gtk_object_ref (GTK_OBJECT (object));
|
||||
|
||||
return object;
|
||||
}
|
||||
#define gst_object_ref gst_object_ref
|
||||
|
||||
/**
|
||||
* gst_object_unref:
|
||||
* @object: GstObject to unreference
|
||||
*
|
||||
* Decrements the refence count on the object. If reference count hits
|
||||
* zero, destroy the object.
|
||||
*/
|
||||
void
|
||||
gst_object_unref (GstObject *object)
|
||||
{
|
||||
g_return_if_fail (GST_IS_OBJECT (object));
|
||||
|
||||
GST_DEBUG (GST_CAT_REFCOUNTING, "unref '%s' %d->%d\n",GST_OBJECT_NAME(object),
|
||||
GTK_OBJECT(object)->ref_count,GTK_OBJECT(object)->ref_count-1);
|
||||
|
||||
gtk_object_unref (GTK_OBJECT (object));
|
||||
}
|
||||
#define gst_object_unref gst_object_unref
|
||||
|
||||
/**
|
||||
* gst_object_sink:
|
||||
* @object: GstObject to sink
|
||||
*
|
||||
* Removes floating reference on an object. Any newly created object has
|
||||
* a refcount of 1 and is FLOATING. This function should be used when
|
||||
* creating a new object to symbolically 'take ownership of' the object.
|
||||
*/
|
||||
void
|
||||
gst_object_sink (GstObject *object)
|
||||
{
|
||||
g_return_if_fail (object != NULL);
|
||||
g_return_if_fail (GST_IS_OBJECT (object));
|
||||
|
||||
GST_DEBUG (GST_CAT_REFCOUNTING, "sink '%s'\n",GST_OBJECT_NAME(object));
|
||||
if (GST_OBJECT_FLOATING (object))
|
||||
{
|
||||
GST_FLAG_UNSET (object, GST_FLOATING);
|
||||
gst_object_unref (object);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gst_object_destroy (GstObject *object)
|
||||
{
|
||||
g_return_if_fail (object != NULL);
|
||||
g_return_if_fail (GST_IS_OBJECT (object));
|
||||
|
||||
GST_DEBUG (GST_CAT_REFCOUNTING, "destroy '%s'\n",GST_OBJECT_NAME(object));
|
||||
if (!GST_OBJECT_DESTROYED (object))
|
||||
{
|
||||
/* need to hold a reference count around all class method
|
||||
* invocations.
|
||||
*/
|
||||
gst_object_ref (object);
|
||||
GTK_OBJECT (object)->klass->shutdown (GTK_OBJECT (object));
|
||||
gst_object_unref (object);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_object_shutdown (GtkObject *object)
|
||||
{
|
||||
GST_DEBUG (GST_CAT_REFCOUNTING, "shutdown '%s'\n",GST_OBJECT_NAME(object));
|
||||
GST_FLAG_SET (GST_OBJECT (object), GST_DESTROYED);
|
||||
parent_class->shutdown (GTK_OBJECT (object));
|
||||
}
|
||||
|
||||
/* finilize is called when the object has to free its resources */
|
||||
static void
|
||||
gst_object_real_destroy (GtkObject *gtk_object)
|
||||
{
|
||||
GST_DEBUG (GST_CAT_REFCOUNTING, "destroy '%s'\n",GST_OBJECT_NAME(gtk_object));
|
||||
|
||||
GST_OBJECT_PARENT (gtk_object) = NULL;
|
||||
|
||||
parent_class->destroy (gtk_object);
|
||||
}
|
||||
|
||||
/* finilize is called when the object has to free its resources */
|
||||
static void
|
||||
gst_object_finalize (GtkObject *gtk_object)
|
||||
{
|
||||
GstObject *object;
|
||||
|
||||
object = GST_OBJECT (gtk_object);
|
||||
|
||||
GST_DEBUG (GST_CAT_REFCOUNTING, "finalize '%s'\n",GST_OBJECT_NAME(object));
|
||||
|
||||
if (object->name != NULL)
|
||||
g_free (object->name);
|
||||
|
||||
g_mutex_free (object->lock);
|
||||
|
||||
parent_class->finalize (gtk_object);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_object_set_name:
|
||||
* @object: GstObject to set the name of
|
||||
|
@ -315,26 +442,31 @@ gst_object_unref (GstObject *object)
|
|||
#endif /* gst_object_unref */
|
||||
|
||||
/**
|
||||
* gst_object_sink:
|
||||
* @object: GstObject to sink
|
||||
* gst_object_check_uniqueness:
|
||||
* @list: a list of #GstObject to check through
|
||||
* @name: the name to search for
|
||||
*
|
||||
* Removes floating reference on an object. Any newly created object has
|
||||
* a refcount of 1 and is FLOATING. This function should be used when
|
||||
* creating a new object to symbolically 'take ownership of' the object.
|
||||
* This function checks through the list of objects to see if the name
|
||||
* given appears in the list as the name of an object. It returns TRUE if
|
||||
* the name does not exist in the list.
|
||||
*
|
||||
* Returns: TRUE if the name doesn't appear in the list, FALSE if it does.
|
||||
*/
|
||||
#ifndef gst_object_sink
|
||||
void
|
||||
gst_object_sink (GstObject *object)
|
||||
gboolean
|
||||
gst_object_check_uniqueness (GList *list, const gchar *name)
|
||||
{
|
||||
g_return_if_fail (object != NULL);
|
||||
g_return_if_fail (GST_IS_OBJECT (object));
|
||||
GstObject *child;
|
||||
|
||||
if (GTK_OBJECT_FLOATING (object)) {
|
||||
GTK_OBJECT_UNSET_FLAGS (object, GTK_FLOATING);
|
||||
gst_object_unref (object);
|
||||
while (list) {
|
||||
child = GST_OBJECT (list->data);
|
||||
list = g_list_next(list);
|
||||
|
||||
if (strcmp(GST_OBJECT_NAME(child), name) == 0) return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif /* gst_object_sink */
|
||||
|
||||
|
||||
/**
|
||||
* gst_object_save_thyself:
|
||||
|
@ -528,6 +660,3 @@ gst_class_signal_emit_by_name (GstObject *object,
|
|||
|
||||
gtk_signal_emit_by_name (oclass->signal_object, name, object, self);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <gst/gsttrace.h>
|
||||
#include <parser.h>
|
||||
|
||||
#include <gst/gsttypes.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
@ -55,10 +57,16 @@ extern "C" {
|
|||
#define GST_IS_OBJECT_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_OBJECT))
|
||||
|
||||
typedef struct _GstObject GstObject;
|
||||
typedef struct _GstObjectClass GstObjectClass;
|
||||
//typedef struct _GstObject GstObject;
|
||||
//typedef struct _GstObjectClass GstObjectClass;
|
||||
//
|
||||
typedef enum
|
||||
{
|
||||
GST_DESTROYED = 0,
|
||||
GST_FLOATING,
|
||||
|
||||
#define GST_OBJECT_FLAG_LAST 4
|
||||
GST_OBJECT_FLAG_LAST = 4,
|
||||
} GstObjectFlags;
|
||||
|
||||
struct _GstObject {
|
||||
GtkObject object;
|
||||
|
@ -76,6 +84,8 @@ struct _GstObject {
|
|||
|
||||
/* this objects parent */
|
||||
GstObject *parent;
|
||||
|
||||
guint32 flags;
|
||||
};
|
||||
|
||||
struct _GstObjectClass {
|
||||
|
@ -89,19 +99,23 @@ struct _GstObjectClass {
|
|||
void (*object_saved) (GstObject *object, xmlNodePtr parent);
|
||||
|
||||
/* functions go here */
|
||||
void (*destroy) (GstObject *object);
|
||||
|
||||
xmlNodePtr (*save_thyself) (GstObject *object, xmlNodePtr parent);
|
||||
void (*restore_thyself) (GstObject *object, xmlNodePtr self);
|
||||
};
|
||||
|
||||
#define GST_OBJECT_NAME(obj) (const gchar*)(((GstObject *)(obj))->name)
|
||||
#define GST_OBJECT_PARENT(obj) (((GstObject *)(obj))->parent)
|
||||
|
||||
|
||||
#define GST_FLAGS(obj) GTK_OBJECT_FLAGS(obj)
|
||||
#define GST_FLAGS(obj) (GST_OBJECT (obj)->flags)
|
||||
#define GST_FLAG_IS_SET(obj,flag) (GST_FLAGS (obj) & (1<<(flag)))
|
||||
#define GST_FLAG_SET(obj,flag) G_STMT_START{ (GST_FLAGS (obj) |= (1<<(flag))); }G_STMT_END
|
||||
#define GST_FLAG_UNSET(obj,flag) G_STMT_START{ (GST_FLAGS (obj) &= ~(1<<(flag))); }G_STMT_END
|
||||
|
||||
#define GST_OBJECT_NAME(obj) (const gchar*)(((GstObject *)(obj))->name)
|
||||
#define GST_OBJECT_PARENT(obj) (((GstObject *)(obj))->parent)
|
||||
|
||||
#define GST_OBJECT_DESTROYED(obj) (GST_FLAG_IS_SET (obj, GST_DESTROYED))
|
||||
#define GST_OBJECT_FLOATING(obj) (GST_FLAG_IS_SET (obj, GST_FLOATING))
|
||||
|
||||
/* object locking */
|
||||
#define GST_LOCK(obj) (g_mutex_lock(GST_OBJECT(obj)->lock))
|
||||
#define GST_TRYLOCK(obj) (g_mutex_trylock(GST_OBJECT(obj)->lock))
|
||||
|
@ -122,15 +136,17 @@ void gst_object_set_parent (GstObject *object,GstObject *parent);
|
|||
GstObject* gst_object_get_parent (GstObject *object);
|
||||
void gst_object_unparent (GstObject *object);
|
||||
|
||||
gboolean gst_object_check_uniqueness (GList *list, const gchar *name);
|
||||
|
||||
xmlNodePtr gst_object_save_thyself (GstObject *object, xmlNodePtr parent);
|
||||
|
||||
/* refcounting */
|
||||
#define gst_object_ref(object) gtk_object_ref(GTK_OBJECT(object));
|
||||
#define gst_object_unref(object) gtk_object_unref(GTK_OBJECT(object));
|
||||
#define gst_object_sink(object) gtk_object_sink(GTK_OBJECT(object));
|
||||
GstObject * gst_object_ref (GstObject *object);
|
||||
void gst_object_unref (GstObject *object);
|
||||
void gst_object_sink (GstObject *object);
|
||||
|
||||
/* destroying an object */
|
||||
#define gst_object_destroy(object) gtk_object_destroy(GTK_OBJECT(object))
|
||||
void gst_object_destroy (GstObject *object);
|
||||
|
||||
/* printing out the 'path' of the object */
|
||||
gchar * gst_object_get_path_string (GstObject *object);
|
||||
|
|
244
gst/gstpad.c
244
gst/gstpad.c
|
@ -27,6 +27,7 @@
|
|||
#include "gstelement.h"
|
||||
#include "gsttype.h"
|
||||
#include "gstbin.h"
|
||||
#include "gstscheduler.h"
|
||||
|
||||
|
||||
/***** Start with the base GstPad class *****/
|
||||
|
@ -78,6 +79,9 @@ gst_pad_init (GstPad *pad)
|
|||
enum {
|
||||
REAL_SET_ACTIVE,
|
||||
REAL_CAPS_CHANGED,
|
||||
REAL_CAPS_NEGO_FAILED,
|
||||
REAL_CONNECTED,
|
||||
REAL_DISCONNECTED,
|
||||
/* FILL ME */
|
||||
REAL_LAST_SIGNAL
|
||||
};
|
||||
|
@ -97,7 +101,6 @@ static void gst_real_pad_get_arg (GtkObject *object,GtkArg *arg,guint id);
|
|||
static void gst_real_pad_destroy (GtkObject *object);
|
||||
|
||||
static void gst_pad_push_func (GstPad *pad, GstBuffer *buf);
|
||||
static gboolean gst_pad_eos_func (GstPad *pad);
|
||||
|
||||
|
||||
static GstPad *real_pad_parent_class = NULL;
|
||||
|
@ -144,16 +147,31 @@ gst_real_pad_class_init (GstRealPadClass *klass)
|
|||
GTK_SIGNAL_OFFSET (GstRealPadClass, caps_changed),
|
||||
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
|
||||
GTK_TYPE_POINTER);
|
||||
gst_real_pad_signals[REAL_CAPS_NEGO_FAILED] =
|
||||
gtk_signal_new ("caps_nego_failed", GTK_RUN_LAST, gtkobject_class->type,
|
||||
GTK_SIGNAL_OFFSET (GstRealPadClass, caps_nego_failed),
|
||||
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
|
||||
GTK_TYPE_POINTER);
|
||||
gst_real_pad_signals[REAL_CONNECTED] =
|
||||
gtk_signal_new ("connected", GTK_RUN_LAST, gtkobject_class->type,
|
||||
GTK_SIGNAL_OFFSET (GstRealPadClass, connected),
|
||||
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
|
||||
GTK_TYPE_POINTER);
|
||||
gst_real_pad_signals[REAL_DISCONNECTED] =
|
||||
gtk_signal_new ("disconnected", GTK_RUN_LAST, gtkobject_class->type,
|
||||
GTK_SIGNAL_OFFSET (GstRealPadClass, disconnected),
|
||||
gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
|
||||
GTK_TYPE_POINTER);
|
||||
gtk_object_class_add_signals (gtkobject_class, gst_real_pad_signals, REAL_LAST_SIGNAL);
|
||||
|
||||
gtk_object_add_arg_type ("GstRealPad::active", GTK_TYPE_BOOL,
|
||||
GTK_ARG_READWRITE, REAL_ARG_ACTIVE);
|
||||
|
||||
gtkobject_class->destroy = gst_real_pad_destroy;
|
||||
gtkobject_class->set_arg = gst_real_pad_set_arg;
|
||||
gtkobject_class->get_arg = gst_real_pad_get_arg;
|
||||
gtkobject_class->destroy = GST_DEBUG_FUNCPTR(gst_real_pad_destroy);
|
||||
gtkobject_class->set_arg = GST_DEBUG_FUNCPTR(gst_real_pad_set_arg);
|
||||
gtkobject_class->get_arg = GST_DEBUG_FUNCPTR(gst_real_pad_get_arg);
|
||||
|
||||
gstobject_class->save_thyself = gst_pad_save_thyself;
|
||||
gstobject_class->save_thyself = GST_DEBUG_FUNCPTR(gst_pad_save_thyself);
|
||||
gstobject_class->path_string_separator = ".";
|
||||
}
|
||||
|
||||
|
@ -167,7 +185,7 @@ gst_real_pad_init (GstRealPad *pad)
|
|||
pad->getfunc = NULL;
|
||||
pad->getregionfunc = NULL;
|
||||
pad->qosfunc = NULL;
|
||||
pad->eosfunc = gst_pad_eos_func;
|
||||
pad->eosfunc = GST_DEBUG_FUNCPTR(gst_pad_eos_func);
|
||||
|
||||
pad->pushfunc = GST_DEBUG_FUNCPTR(gst_pad_push_func);
|
||||
pad->pullfunc = NULL;
|
||||
|
@ -260,6 +278,8 @@ gst_pad_new_from_template (GstPadTemplate *templ,
|
|||
g_return_val_if_fail (templ != NULL, NULL);
|
||||
|
||||
pad = gst_pad_new (name, templ->direction);
|
||||
gst_object_ref (GST_OBJECT (templ));
|
||||
gst_object_sink (GST_OBJECT (templ));
|
||||
GST_PAD_PADTEMPLATE(pad) = templ;
|
||||
|
||||
return pad;
|
||||
|
@ -330,8 +350,8 @@ void gst_pad_set_chain_function (GstPad *pad,
|
|||
g_return_if_fail (GST_IS_REAL_PAD (pad));
|
||||
|
||||
GST_RPAD_CHAINFUNC(pad) = chain;
|
||||
GST_DEBUG (0,"chainfunc for %s:%s(@%p) at %p is set to %p\n",
|
||||
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_CHAINFUNC(pad),chain);
|
||||
GST_DEBUG (GST_CAT_PADS,"chainfunc for %s:%s set to %s\n",
|
||||
GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(chain));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -349,8 +369,8 @@ gst_pad_set_get_function (GstPad *pad,
|
|||
g_return_if_fail (GST_IS_REAL_PAD (pad));
|
||||
|
||||
GST_RPAD_GETFUNC(pad) = get;
|
||||
GST_DEBUG (0,"getfunc for %s:%s(@%p) at %p is set to %p\n",
|
||||
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_GETFUNC(pad),get);
|
||||
GST_DEBUG (GST_CAT_PADS,"getfunc for %s:%s set to %s\n",
|
||||
GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(get));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -368,8 +388,8 @@ gst_pad_set_getregion_function (GstPad *pad,
|
|||
g_return_if_fail (GST_IS_REAL_PAD (pad));
|
||||
|
||||
GST_RPAD_GETREGIONFUNC(pad) = getregion;
|
||||
GST_DEBUG (0,"getregionfunc for %s:%s(@%p) at %p is set to %p\n",
|
||||
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_GETREGIONFUNC(pad),getregion);
|
||||
GST_DEBUG (GST_CAT_PADS,"getregionfunc for %s:%s set to %s\n",
|
||||
GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(getregion));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -387,8 +407,8 @@ gst_pad_set_qos_function (GstPad *pad,
|
|||
g_return_if_fail (GST_IS_REAL_PAD (pad));
|
||||
|
||||
GST_RPAD_QOSFUNC(pad) = qos;
|
||||
GST_DEBUG (0,"qosfunc for %s:%s(@%p) at %p is set to %p\n",
|
||||
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_QOSFUNC(pad),qos);
|
||||
GST_DEBUG (GST_CAT_PADS,"qosfunc for %s:%s set to %s\n",
|
||||
GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(qos));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -406,8 +426,8 @@ gst_pad_set_eos_function (GstPad *pad,
|
|||
g_return_if_fail (GST_IS_REAL_PAD (pad));
|
||||
|
||||
GST_RPAD_EOSFUNC(pad) = eos;
|
||||
GST_DEBUG (0,"eosfunc for %s:%s(@%p) at %p is set to %p\n",
|
||||
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_EOSFUNC(pad),eos);
|
||||
GST_DEBUG (GST_CAT_PADS,"eosfunc for %s:%s set to %s\n",
|
||||
GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(eos));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -425,11 +445,10 @@ gst_pad_set_negotiate_function (GstPad *pad,
|
|||
g_return_if_fail (GST_IS_REAL_PAD (pad));
|
||||
|
||||
GST_RPAD_NEGOTIATEFUNC(pad) = nego;
|
||||
GST_DEBUG (0,"negotiatefunc for %s:%s(@%p) at %p is set to %p\n",
|
||||
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_NEGOTIATEFUNC(pad),nego);
|
||||
GST_DEBUG (GST_CAT_PADS,"negotiatefunc for %s:%s set to %s\n",
|
||||
GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(nego));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_pad_set_newcaps_function:
|
||||
* @pad: the pad to set the newcaps function for
|
||||
|
@ -445,8 +464,8 @@ gst_pad_set_newcaps_function (GstPad *pad,
|
|||
g_return_if_fail (GST_IS_REAL_PAD (pad));
|
||||
|
||||
GST_RPAD_NEWCAPSFUNC (pad) = newcaps;
|
||||
GST_DEBUG (0,"newcapsfunc for %s:%s(@%p) at %p is set to %p\n",
|
||||
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_NEWCAPSFUNC(pad),newcaps);
|
||||
GST_DEBUG (GST_CAT_PADS,"newcapsfunc for %s:%s set to %s\n",
|
||||
GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(newcaps));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -464,18 +483,19 @@ gst_pad_set_bufferpool_function (GstPad *pad,
|
|||
g_return_if_fail (GST_IS_REAL_PAD (pad));
|
||||
|
||||
GST_RPAD_BUFFERPOOLFUNC (pad) = bufpool;
|
||||
GST_DEBUG (0,"bufferpoolfunc for %s:%s(@%p) at %p is set to %p\n",
|
||||
GST_DEBUG_PAD_NAME (pad), pad, &GST_RPAD_BUFFERPOOLFUNC (pad), bufpool);
|
||||
GST_DEBUG (GST_CAT_PADS,"bufferpoolfunc for %s:%s set to %s\n",
|
||||
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME(bufpool));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_pad_push_func(GstPad *pad, GstBuffer *buf)
|
||||
{
|
||||
if (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)) != NULL) {
|
||||
GST_DEBUG (0,"calling chain function\n");
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"calling chain function %s\n",
|
||||
GST_DEBUG_FUNCPTR_NAME(GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad))));
|
||||
(GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)))(pad,buf);
|
||||
} else {
|
||||
GST_DEBUG (0,"got a problem here: default pad_push handler in place, no chain function\n");
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"got a problem here: default pad_push handler in place, no chain function\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,7 +515,7 @@ gst_pad_handle_qos(GstPad *pad,
|
|||
GList *pads;
|
||||
GstPad *target_pad;
|
||||
|
||||
GST_DEBUG (0,"gst_pad_handle_qos(\"%s\",%08ld)\n", GST_OBJECT_NAME (GST_PAD_PARENT (pad)),qos_message);
|
||||
GST_DEBUG (GST_CAT_PADS,"gst_pad_handle_qos(\"%s\",%08ld)\n", GST_OBJECT_NAME (GST_PAD_PARENT (pad)),qos_message);
|
||||
|
||||
if (GST_RPAD_QOSFUNC(pad)) {
|
||||
(GST_RPAD_QOSFUNC(pad)) (pad,qos_message);
|
||||
|
@ -503,7 +523,7 @@ gst_pad_handle_qos(GstPad *pad,
|
|||
element = GST_ELEMENT (GST_PAD_PARENT(GST_RPAD_PEER(pad)));
|
||||
|
||||
pads = element->pads;
|
||||
GST_DEBUG (0,"gst_pad_handle_qos recurse(\"%s\",%08ld)\n", GST_ELEMENT_NAME (element), qos_message);
|
||||
GST_DEBUG (GST_CAT_PADS,"gst_pad_handle_qos recurse(\"%s\",%08ld)\n", GST_ELEMENT_NAME (element), qos_message);
|
||||
while (pads) {
|
||||
target_pad = GST_PAD (pads->data);
|
||||
if (GST_RPAD_DIRECTION(target_pad) == GST_PAD_SINK) {
|
||||
|
@ -535,6 +555,9 @@ gst_pad_disconnect (GstPad *srcpad,
|
|||
g_return_if_fail (sinkpad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (sinkpad));
|
||||
|
||||
GST_INFO (GST_CAT_ELEMENT_PADS, "disconnecting %s:%s(%p) and %s:%s(%p)",
|
||||
GST_DEBUG_PAD_NAME(srcpad), srcpad, GST_DEBUG_PAD_NAME(sinkpad), sinkpad);
|
||||
|
||||
// now we need to deal with the real/ghost stuff
|
||||
realsrc = GST_PAD_REALIZE(srcpad);
|
||||
realsink = GST_PAD_REALIZE(sinkpad);
|
||||
|
@ -542,6 +565,14 @@ gst_pad_disconnect (GstPad *srcpad,
|
|||
g_return_if_fail (GST_RPAD_PEER(realsrc) != NULL);
|
||||
g_return_if_fail (GST_RPAD_PEER(realsink) != NULL);
|
||||
|
||||
if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) &&
|
||||
(GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) {
|
||||
GstRealPad *temppad;
|
||||
|
||||
temppad = realsrc;
|
||||
realsrc = realsink;
|
||||
realsink = temppad;
|
||||
}
|
||||
g_return_if_fail ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) &&
|
||||
(GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK));
|
||||
|
||||
|
@ -549,6 +580,16 @@ gst_pad_disconnect (GstPad *srcpad,
|
|||
GST_RPAD_PEER(realsrc) = NULL;
|
||||
GST_RPAD_PEER(realsink) = NULL;
|
||||
|
||||
/* fire off a signal to each of the pads telling them that they've been disconnected */
|
||||
gtk_signal_emit(GTK_OBJECT(realsrc), gst_real_pad_signals[REAL_DISCONNECTED], realsink);
|
||||
gtk_signal_emit(GTK_OBJECT(realsink), gst_real_pad_signals[REAL_DISCONNECTED], realsrc);
|
||||
|
||||
// now tell the scheduler
|
||||
if (realsrc->sched)
|
||||
GST_SCHEDULE_PAD_DISCONNECT (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink);
|
||||
// if (realsink->sched)
|
||||
// GST_SCHEDULE_PAD_DISCONNECT (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink);
|
||||
|
||||
GST_INFO (GST_CAT_ELEMENT_PADS, "disconnected %s:%s and %s:%s",
|
||||
GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
|
||||
}
|
||||
|
@ -567,7 +608,6 @@ gst_pad_connect (GstPad *srcpad,
|
|||
GstPad *sinkpad)
|
||||
{
|
||||
GstRealPad *realsrc, *realsink;
|
||||
GstRealPad *temppad;
|
||||
gboolean negotiated = FALSE;
|
||||
|
||||
/* generic checks */
|
||||
|
@ -576,19 +616,25 @@ gst_pad_connect (GstPad *srcpad,
|
|||
g_return_val_if_fail(sinkpad != NULL, FALSE);
|
||||
g_return_val_if_fail(GST_IS_PAD(sinkpad), FALSE);
|
||||
|
||||
GST_INFO (GST_CAT_ELEMENT_PADS, "about to connect %s:%s and %s:%s",
|
||||
GST_INFO (GST_CAT_PADS, "connecting %s:%s and %s:%s",
|
||||
GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
|
||||
|
||||
// now we need to deal with the real/ghost stuff
|
||||
realsrc = GST_PAD_REALIZE(srcpad);
|
||||
realsink = GST_PAD_REALIZE(sinkpad);
|
||||
|
||||
if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad))
|
||||
GST_INFO (GST_CAT_PADS, "*actually* connecting %s:%s and %s:%s",
|
||||
GST_DEBUG_PAD_NAME(realsrc), GST_DEBUG_PAD_NAME(realsink));
|
||||
|
||||
g_return_val_if_fail(GST_RPAD_PEER(realsrc) == NULL, FALSE);
|
||||
g_return_val_if_fail(GST_RPAD_PEER(realsink) == NULL, FALSE);
|
||||
|
||||
/* check for reversed directions and swap if necessary */
|
||||
if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) &&
|
||||
(GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) {
|
||||
GstRealPad *temppad;
|
||||
|
||||
temppad = realsrc;
|
||||
realsrc = realsink;
|
||||
realsink = temppad;
|
||||
|
@ -601,24 +647,38 @@ gst_pad_connect (GstPad *srcpad,
|
|||
GST_RPAD_PEER(realsrc) = realsink;
|
||||
GST_RPAD_PEER(realsink) = realsrc;
|
||||
|
||||
/* FIXME: set connected flag */
|
||||
|
||||
GST_INFO (GST_CAT_ELEMENT_PADS, "connected %s:%s and %s:%s",
|
||||
GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
|
||||
|
||||
if (GST_PAD_CAPS (srcpad)) {
|
||||
GST_DEBUG(GST_CAT_PADS, "renegotiation from srcpad\n");
|
||||
negotiated = gst_pad_renegotiate (srcpad);
|
||||
}
|
||||
else if (GST_PAD_CAPS (sinkpad)) {
|
||||
GST_DEBUG(GST_CAT_PADS, "renegotiation from sinkpad\n");
|
||||
negotiated = gst_pad_renegotiate (sinkpad);
|
||||
}
|
||||
else
|
||||
else {
|
||||
GST_DEBUG(GST_CAT_PADS, "not renegotiating connection\n");
|
||||
negotiated = TRUE;
|
||||
}
|
||||
|
||||
if (!negotiated) {
|
||||
GST_INFO(GST_CAT_PADS, "pads %s:%s and %s:%s failed to negotiate, disconnecting",
|
||||
GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
|
||||
gst_pad_disconnect (GST_PAD (realsrc), GST_PAD (realsink));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* fire off a signal to each of the pads telling them that they've been connected */
|
||||
gtk_signal_emit(GTK_OBJECT(realsrc), gst_real_pad_signals[REAL_CONNECTED], realsink);
|
||||
gtk_signal_emit(GTK_OBJECT(realsink), gst_real_pad_signals[REAL_CONNECTED], realsrc);
|
||||
|
||||
// now tell the scheduler(s)
|
||||
if (realsrc->sched)
|
||||
GST_SCHEDULE_PAD_CONNECT (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink);
|
||||
else if (realsink->sched)
|
||||
GST_SCHEDULE_PAD_CONNECT (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink);
|
||||
|
||||
GST_INFO (GST_CAT_PADS, "connected %s:%s and %s:%s",
|
||||
GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -668,13 +728,31 @@ gst_pad_get_padtemplate (GstPad *pad)
|
|||
*
|
||||
* Returns: the parent object
|
||||
*/
|
||||
GstObject*
|
||||
GstElement*
|
||||
gst_pad_get_parent (GstPad *pad)
|
||||
{
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||
|
||||
return GST_OBJECT_PARENT (pad);
|
||||
return GST_PAD_PARENT (pad);
|
||||
}
|
||||
|
||||
void
|
||||
gst_pad_set_sched (GstPad *pad, GstSchedule *sched)
|
||||
{
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
|
||||
GST_RPAD_SCHED(pad) = sched;
|
||||
}
|
||||
|
||||
GstSchedule*
|
||||
gst_pad_get_sched (GstPad *pad)
|
||||
{
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||
|
||||
return GST_RPAD_SCHED(pad);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -687,7 +765,7 @@ gst_pad_get_parent (GstPad *pad)
|
|||
*
|
||||
* Returns: the parent object
|
||||
*/
|
||||
GstObject*
|
||||
GstElement*
|
||||
gst_pad_get_real_parent (GstPad *pad)
|
||||
{
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
|
@ -892,7 +970,7 @@ gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
|
|||
}
|
||||
}
|
||||
else {
|
||||
GST_DEBUG (0,"gstpad: could not check capabilities of pads (%s:%s) and (%s:%s) %p %p\n",
|
||||
GST_DEBUG (GST_CAT_PADS,"could not check capabilities of pads (%s:%s) and (%s:%s) %p %p\n",
|
||||
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad),
|
||||
GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad));
|
||||
return TRUE;
|
||||
|
@ -940,27 +1018,53 @@ gst_pad_get_bufferpool (GstPad *pad)
|
|||
GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
|
||||
|
||||
if (peer->bufferpoolfunc) {
|
||||
GST_DEBUG (0,"calling bufferpoolfunc &%s (@%p) of peer pad %s:%s\n",
|
||||
GST_DEBUG (GST_CAT_PADS,"calling bufferpoolfunc &%s (@%p) of peer pad %s:%s\n",
|
||||
GST_DEBUG_FUNCPTR_NAME(peer->bufferpoolfunc),&peer->bufferpoolfunc,GST_DEBUG_PAD_NAME(((GstPad*)peer)));
|
||||
return (peer->bufferpoolfunc)(((GstPad*)peer));
|
||||
} else {
|
||||
GST_DEBUG (0,"no bufferpoolfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->bufferpoolfunc);
|
||||
GST_DEBUG (GST_CAT_PADS,"no bufferpoolfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->bufferpoolfunc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FIXME this needs to be rethought soon
|
||||
static void
|
||||
gst_real_pad_destroy (GtkObject *object)
|
||||
{
|
||||
GstPad *pad = GST_PAD (object);
|
||||
|
||||
// g_print("in gst_pad_real_destroy()\n");
|
||||
GST_DEBUG (GST_CAT_REFCOUNTING, "destroy %s:%s\n", GST_DEBUG_PAD_NAME(pad));
|
||||
|
||||
if (GST_PAD (pad)->padtemplate)
|
||||
gst_object_unref (GST_OBJECT (GST_PAD (pad)->padtemplate));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_pad_load_and_connect:
|
||||
|
@ -1170,9 +1274,22 @@ gst_pad_renegotiate (GstPad *pad)
|
|||
|
||||
result = gst_pad_renegotiate_func (GST_PAD (currentpad), &data1, GST_PAD (otherpad), &data2, &newcaps);
|
||||
|
||||
if (!result) {
|
||||
GST_DEBUG (GST_CAT_NEGOTIATION, "firing caps_nego_failed signal on %s:%s and %s:%s to give it a chance to succeed\n",
|
||||
GST_DEBUG_PAD_NAME(currentpad),GST_DEBUG_PAD_NAME(otherpad));
|
||||
gtk_signal_emit (GTK_OBJECT(currentpad),
|
||||
gst_real_pad_signals[REAL_CAPS_NEGO_FAILED],&result);
|
||||
gtk_signal_emit (GTK_OBJECT(otherpad),
|
||||
gst_real_pad_signals[REAL_CAPS_NEGO_FAILED],&result);
|
||||
if (result)
|
||||
GST_DEBUG (GST_CAT_NEGOTIATION, "caps_nego_failed handler claims success at renego, believing\n");
|
||||
}
|
||||
|
||||
if (result) {
|
||||
GST_DEBUG (GST_CAT_NEGOTIATION, "pads aggreed on caps :)\n");
|
||||
|
||||
newcaps = GST_PAD_CAPS (pad);
|
||||
|
||||
/* here we have some sort of aggreement of the caps */
|
||||
GST_PAD_CAPS (currentpad) = gst_caps_ref (newcaps);
|
||||
if (GST_RPAD_NEWCAPSFUNC (currentpad))
|
||||
|
@ -1181,6 +1298,13 @@ gst_pad_renegotiate (GstPad *pad)
|
|||
GST_PAD_CAPS (otherpad) = gst_caps_ref (newcaps);
|
||||
if (GST_RPAD_NEWCAPSFUNC (otherpad))
|
||||
GST_RPAD_NEWCAPSFUNC (otherpad) (GST_PAD (otherpad), newcaps);
|
||||
|
||||
GST_DEBUG (GST_CAT_NEGOTIATION, "firing caps_changed signal on %s:%s and %s:%s\n",
|
||||
GST_DEBUG_PAD_NAME(currentpad),GST_DEBUG_PAD_NAME(otherpad));
|
||||
gtk_signal_emit (GTK_OBJECT(currentpad),
|
||||
gst_real_pad_signals[REAL_CAPS_CHANGED],GST_PAD_CAPS(currentpad));
|
||||
gtk_signal_emit (GTK_OBJECT(otherpad),
|
||||
gst_real_pad_signals[REAL_CAPS_CHANGED],GST_PAD_CAPS(otherpad));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1313,16 +1437,16 @@ gst_pad_push (GstPad *pad, GstBuffer *buf)
|
|||
{
|
||||
GstRealPad *peer = GST_RPAD_PEER (pad);
|
||||
|
||||
g_return_if_fail (peer != NULL);
|
||||
|
||||
GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
g_return_if_fail (peer != NULL);
|
||||
|
||||
if (peer->pushfunc) {
|
||||
GST_DEBUG (0, "calling pushfunc &%s of peer pad %s:%s\n",
|
||||
GST_DEBUG (GST_CAT_DATAFLOW, "calling pushfunc &%s of peer pad %s:%s\n",
|
||||
GST_DEBUG_FUNCPTR_NAME (peer->pushfunc), GST_DEBUG_PAD_NAME (((GstPad*)peer)));
|
||||
(peer->pushfunc) (((GstPad*)peer), buf);
|
||||
} else
|
||||
GST_DEBUG (0, "no pushfunc\n");
|
||||
GST_DEBUG (GST_CAT_DATAFLOW, "no pushfunc\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1340,16 +1464,16 @@ gst_pad_pull (GstPad *pad)
|
|||
{
|
||||
GstRealPad *peer = GST_RPAD_PEER(pad);
|
||||
|
||||
g_return_val_if_fail (peer != NULL, NULL);
|
||||
|
||||
GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
|
||||
|
||||
g_return_val_if_fail (peer != NULL, NULL);
|
||||
|
||||
if (peer->pullfunc) {
|
||||
GST_DEBUG (0,"calling pullfunc &%s (@%p) of peer pad %s:%s\n",
|
||||
GST_DEBUG_FUNCPTR_NAME(peer->pullfunc),&peer->pullfunc,GST_DEBUG_PAD_NAME(((GstPad*)peer)));
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"calling pullfunc %s of peer pad %s:%s\n",
|
||||
GST_DEBUG_FUNCPTR_NAME(peer->pullfunc),GST_DEBUG_PAD_NAME(peer));
|
||||
return (peer->pullfunc)(((GstPad*)peer));
|
||||
} else {
|
||||
GST_DEBUG (0,"no pullfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->pullfunc);
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"no pullfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->pullfunc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1380,11 +1504,11 @@ gst_pad_pullregion (GstPad *pad, GstRegionType type, guint64 offset, guint64 len
|
|||
GST_DEBUG_ENTER("(%s:%s,%d,%lld,%lld)",GST_DEBUG_PAD_NAME(pad),type,offset,len);
|
||||
|
||||
if (peer->pullregionfunc) {
|
||||
GST_DEBUG (0,"calling pullregionfunc &%s of peer pad %s:%s\n",
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"calling pullregionfunc &%s of peer pad %s:%s\n",
|
||||
GST_DEBUG_FUNCPTR_NAME(peer->pullregionfunc),GST_DEBUG_PAD_NAME(((GstPad*)peer)));
|
||||
return (peer->pullregionfunc)(((GstPad*)peer),type,offset,len);
|
||||
} else {
|
||||
GST_DEBUG (0,"no pullregionfunc\n");
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"no pullregionfunc\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1528,7 +1652,7 @@ gst_padtemplate_save_thyself (GstPadTemplate *templ, xmlNodePtr parent)
|
|||
xmlNodePtr subtree;
|
||||
guchar *presence;
|
||||
|
||||
GST_DEBUG (0,"saving padtemplate %s\n", templ->name_template);
|
||||
GST_DEBUG (GST_CAT_XML,"saving padtemplate %s\n", templ->name_template);
|
||||
|
||||
xmlNewChild(parent,NULL,"nametemplate", templ->name_template);
|
||||
xmlNewChild(parent,NULL,"direction", (templ->direction == GST_PAD_SINK? "sink":"src"));
|
||||
|
@ -1616,7 +1740,7 @@ gst_padtemplate_load_thyself (xmlNodePtr parent)
|
|||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gboolean
|
||||
gst_pad_eos_func(GstPad *pad)
|
||||
{
|
||||
GstElement *element;
|
||||
|
@ -1649,6 +1773,8 @@ gst_pad_eos_func(GstPad *pad)
|
|||
GST_INFO (GST_CAT_PADS,"set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad));
|
||||
GST_FLAG_SET (pad, GST_PAD_EOS);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT(GST_PAD_PARENT(pad)), GST_STATE_READY);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1676,6 +1802,8 @@ gst_pad_set_eos(GstPad *pad)
|
|||
GST_INFO (GST_CAT_PADS,"set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad));
|
||||
GST_FLAG_SET (pad, GST_PAD_EOS);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT(GST_PAD_PARENT(pad)), GST_STATE_READY);
|
||||
|
||||
gst_element_signal_eos (GST_ELEMENT (GST_PAD_PARENT (pad)));
|
||||
|
||||
return TRUE;
|
||||
|
@ -1783,7 +1911,7 @@ gst_ghost_pad_new (gchar *name,
|
|||
|
||||
// FIXME need to ref the real pad here... ?
|
||||
|
||||
GST_DEBUG(0,"created ghost pad \"%s\"\n",name);
|
||||
GST_DEBUG(GST_CAT_PADS,"created ghost pad \"%s\"\n",name);
|
||||
|
||||
return GST_PAD(ghostpad);
|
||||
}
|
||||
|
|
26
gst/gstpad.h
26
gst/gstpad.h
|
@ -63,14 +63,14 @@ extern "C" {
|
|||
#define GST_IS_GHOST_PAD_CLASS(obj) (GTK_CHECK_CLASS_TYPE ((klass), GST_TYPE_GHOST_PAD))
|
||||
|
||||
|
||||
typedef struct _GstPad GstPad;
|
||||
typedef struct _GstPadClass GstPadClass;
|
||||
//typedef struct _GstPad GstPad;
|
||||
//typedef struct _GstPadClass GstPadClass;
|
||||
typedef struct _GstRealPad GstRealPad;
|
||||
typedef struct _GstRealPadClass GstRealPadClass;
|
||||
typedef struct _GstGhostPad GstGhostPad;
|
||||
typedef struct _GstGhostPadClass GstGhostPadClass;
|
||||
typedef struct _GstPadTemplate GstPadTemplate;
|
||||
typedef struct _GstPadTemplateClass GstPadTemplateClass;
|
||||
//typedef struct _GstPadTemplate GstPadTemplate;
|
||||
//typedef struct _GstPadTemplateClass GstPadTemplateClass;
|
||||
|
||||
|
||||
typedef enum {
|
||||
|
@ -142,6 +142,8 @@ struct _GstRealPad {
|
|||
guint64 offset;
|
||||
guint64 len;
|
||||
|
||||
GstSchedule *sched;
|
||||
|
||||
GstPadChainFunction chainfunc;
|
||||
GstPadGetFunction getfunc;
|
||||
GstPadGetRegionFunction getregionfunc;
|
||||
|
@ -165,6 +167,10 @@ struct _GstRealPadClass {
|
|||
/* signal callbacks */
|
||||
void (*set_active) (GstPad *pad, gboolean active);
|
||||
void (*caps_changed) (GstPad *pad, GstCaps *newcaps);
|
||||
void (*caps_nego_failed) (GstPad *pad);
|
||||
void (*connected) (GstPad *pad, GstPad *peer);
|
||||
void (*disconnected) (GstPad *pad, GstPad *peer);
|
||||
|
||||
void (*eos) (GstPad *pad);
|
||||
};
|
||||
|
||||
|
@ -182,7 +188,7 @@ struct _GstGhostPadClass {
|
|||
/***** helper macros *****/
|
||||
/* GstPad */
|
||||
#define GST_PAD_NAME(pad) (GST_OBJECT_NAME(pad))
|
||||
#define GST_PAD_PARENT(pad) (GST_OBJECT_PARENT(pad))
|
||||
#define GST_PAD_PARENT(pad) ((GstElement *)(GST_OBJECT_PARENT(pad)))
|
||||
#define GST_PAD_ELEMENT_PRIVATE(pad) (((GstPad *)(pad))->element_private)
|
||||
#define GST_PAD_PADTEMPLATE(pad) (((GstPad *)(pad))->padtemplate)
|
||||
|
||||
|
@ -191,6 +197,7 @@ struct _GstGhostPadClass {
|
|||
#define GST_RPAD_CAPS(pad) (((GstRealPad *)(pad))->caps)
|
||||
#define GST_RPAD_PEER(pad) (((GstRealPad *)(pad))->peer)
|
||||
#define GST_RPAD_BUFPEN(pad) (((GstRealPad *)(pad))->bufpen)
|
||||
#define GST_RPAD_SCHED(pad) (((GstRealPad *)(pad))->sched)
|
||||
#define GST_RPAD_CHAINFUNC(pad) (((GstRealPad *)(pad))->chainfunc)
|
||||
#define GST_RPAD_GETFUNC(pad) (((GstRealPad *)(pad))->getfunc)
|
||||
#define GST_RPAD_GETREGIONFUNC(pad) (((GstRealPad *)(pad))->getregionfunc)
|
||||
|
@ -312,8 +319,11 @@ void gst_pad_set_name (GstPad *pad, const gchar *name);
|
|||
const gchar* gst_pad_get_name (GstPad *pad);
|
||||
|
||||
void gst_pad_set_parent (GstPad *pad, GstObject *parent);
|
||||
GstObject* gst_pad_get_parent (GstPad *pad);
|
||||
GstObject* gst_pad_get_real_parent (GstPad *pad);
|
||||
GstElement* gst_pad_get_parent (GstPad *pad);
|
||||
GstElement* gst_pad_get_real_parent (GstPad *pad);
|
||||
|
||||
void gst_pad_set_sched (GstPad *pad, GstSchedule *sched);
|
||||
GstSchedule* gst_pad_get_sched (GstPad *pad);
|
||||
|
||||
void gst_pad_add_ghost_pad (GstPad *pad, GstPad *ghostpad);
|
||||
void gst_pad_remove_ghost_pad (GstPad *pad, GstPad *ghostpad);
|
||||
|
@ -356,6 +366,7 @@ NULL )
|
|||
#define gst_pad_eos(pad) (GST_RPAD_EOSFUNC(GST_RPAD_PEER(pad))(GST_PAD(GST_RPAD_PEER(pad))))
|
||||
gboolean gst_pad_set_eos (GstPad *pad);
|
||||
|
||||
gboolean gst_pad_eos_func (GstPad *pad);
|
||||
void gst_pad_handle_qos (GstPad *pad, glong qos_message);
|
||||
|
||||
void gst_pad_load_and_connect (xmlNodePtr self, GstObject *parent);
|
||||
|
@ -379,6 +390,7 @@ GstCaps* gst_padtemplate_get_caps_by_name (GstPadTemplate *templ, const gchar *
|
|||
xmlNodePtr gst_padtemplate_save_thyself (GstPadTemplate *templ, xmlNodePtr parent);
|
||||
GstPadTemplate* gst_padtemplate_load_thyself (xmlNodePtr parent);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
#include "gst_private.h"
|
||||
|
||||
#include "gstpipeline.h"
|
||||
#include "gstthread.h"
|
||||
#include "gstutils.h"
|
||||
#include "gsttype.h"
|
||||
#include "gstautoplug.h"
|
||||
#include "gstscheduler.h"
|
||||
|
||||
|
||||
GstElementDetails gst_pipeline_details = {
|
||||
|
@ -95,6 +100,10 @@ gst_pipeline_init (GstPipeline *pipeline)
|
|||
{
|
||||
// we're a manager by default
|
||||
GST_FLAG_SET (pipeline, GST_BIN_FLAG_MANAGER);
|
||||
|
||||
GST_ELEMENT_SCHED(pipeline) = gst_schedule_new(GST_ELEMENT(pipeline));
|
||||
GST_DEBUG(GST_CAT_PIPELINE, "pipeline's scheduler is %p\n",GST_ELEMENT_SCHED(pipeline));
|
||||
// gst_element_set_manager(GST_ELEMENT(pipeline),GST_ELEMENT(pipeline));
|
||||
}
|
||||
|
||||
|
||||
|
@ -115,7 +124,7 @@ gst_pipeline_new (const guchar *name)
|
|||
static void
|
||||
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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -53,19 +53,19 @@ gst_props_debug_entry (GstPropsEntry *entry)
|
|||
{
|
||||
switch (entry->propstype) {
|
||||
case GST_PROPS_INT_ID:
|
||||
GST_DEBUG (0, "%d\n", entry->data.int_data);
|
||||
GST_DEBUG (GST_CAT_PROPERTIES, "%d\n", entry->data.int_data);
|
||||
break;
|
||||
case GST_PROPS_FOURCC_ID:
|
||||
GST_DEBUG (0, "%4.4s\n", (gchar*)&entry->data.fourcc_data);
|
||||
GST_DEBUG (GST_CAT_PROPERTIES, "%4.4s\n", (gchar*)&entry->data.fourcc_data);
|
||||
break;
|
||||
case GST_PROPS_BOOL_ID:
|
||||
GST_DEBUG (0, "%d\n", entry->data.bool_data);
|
||||
GST_DEBUG (GST_CAT_PROPERTIES, "%d\n", entry->data.bool_data);
|
||||
break;
|
||||
case GST_PROPS_STRING_ID:
|
||||
GST_DEBUG (0, "%s\n", entry->data.string_data.string);
|
||||
GST_DEBUG (GST_CAT_PROPERTIES, "%s\n", entry->data.string_data.string);
|
||||
break;
|
||||
case GST_PROPS_INT_RANGE_ID:
|
||||
GST_DEBUG (0, "%d-%d\n", entry->data.int_range_data.min,
|
||||
GST_DEBUG (GST_CAT_PROPERTIES, "%d-%d\n", entry->data.int_range_data.min,
|
||||
entry->data.int_range_data.max);
|
||||
break;
|
||||
default:
|
||||
|
@ -616,7 +616,7 @@ gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *
|
|||
static gboolean
|
||||
gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
|
||||
{
|
||||
GST_DEBUG (0,"compare: %s %s\n", g_quark_to_string (entry1->propid),
|
||||
GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s\n", g_quark_to_string (entry1->propid),
|
||||
g_quark_to_string (entry2->propid));
|
||||
switch (entry1->propstype) {
|
||||
case GST_PROPS_LIST_ID:
|
||||
|
@ -674,10 +674,13 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry
|
|||
switch (entry2->propstype) {
|
||||
// b <---> a - d
|
||||
case GST_PROPS_INT_RANGE_ID:
|
||||
GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?\n",entry2->data.int_range_data.min,
|
||||
entry1->data.int_data,entry2->data.int_range_data.max);
|
||||
return (entry2->data.int_range_data.min <= entry1->data.int_data &&
|
||||
entry2->data.int_range_data.max >= entry1->data.int_data);
|
||||
// b <---> a
|
||||
case GST_PROPS_INT_ID:
|
||||
GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?\n",entry1->data.int_data,entry2->data.int_data);
|
||||
return (entry2->data.int_data == entry1->data.int_data);
|
||||
// b <---> a,b,c
|
||||
case GST_PROPS_LIST_ID:
|
||||
|
@ -761,14 +764,14 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
|
|||
entry2 = (GstPropsEntry *)sinklist->data;
|
||||
|
||||
while (entry1->propid < entry2->propid) {
|
||||
GST_DEBUG (0,"source is more specific in \"%s\"\n", g_quark_to_string (entry1->propid));
|
||||
GST_DEBUG (GST_CAT_PROPERTIES,"source is more specific in \"%s\"\n", g_quark_to_string (entry1->propid));
|
||||
more++;
|
||||
sourcelist = g_list_next (sourcelist);
|
||||
if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
|
||||
else goto end;
|
||||
}
|
||||
while (entry1->propid > entry2->propid) {
|
||||
GST_DEBUG (0,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
|
||||
GST_DEBUG (GST_CAT_PROPERTIES,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
|
||||
missing++;
|
||||
sinklist = g_list_next (sinklist);
|
||||
if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
|
||||
|
@ -777,7 +780,7 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
|
|||
|
||||
if (!gst_props_entry_check_compatibility (entry1, entry2)) {
|
||||
compatible = FALSE;
|
||||
GST_DEBUG (0, "%s are not compatible\n:",
|
||||
GST_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: \n",
|
||||
g_quark_to_string (entry1->propid));
|
||||
gst_props_debug_entry (entry1);
|
||||
gst_props_debug_entry (entry2);
|
||||
|
@ -790,7 +793,7 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
|
|||
GstPropsEntry *entry2;
|
||||
entry2 = (GstPropsEntry *)sinklist->data;
|
||||
missing++;
|
||||
GST_DEBUG (0,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
|
||||
GST_DEBUG (GST_CAT_PROPERTIES,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
|
||||
}
|
||||
end:
|
||||
|
||||
|
|
247
gst/gstqueue.c
247
gst/gstqueue.c
|
@ -23,7 +23,7 @@
|
|||
//#define DEBUG_ENABLED
|
||||
//#define STATUS_ENABLED
|
||||
#ifdef STATUS_ENABLED
|
||||
#define STATUS(A) GST_DEBUG(0,A, gst_element_get_name(GST_ELEMENT(queue)))
|
||||
#define STATUS(A) GST_DEBUG(GST_CAT_DATAFLOW, A, GST_ELEMENT_NAME(queue))
|
||||
#else
|
||||
#define STATUS(A)
|
||||
#endif
|
||||
|
@ -34,6 +34,7 @@
|
|||
#include "gst_private.h"
|
||||
|
||||
#include "gstqueue.h"
|
||||
#include "gstscheduler.h"
|
||||
|
||||
GstElementDetails gst_queue_details = {
|
||||
"Queue",
|
||||
|
@ -47,15 +48,22 @@ GstElementDetails gst_queue_details = {
|
|||
|
||||
/* Queue signals and args */
|
||||
enum {
|
||||
/* FILL ME */
|
||||
LOW_WATERMARK,
|
||||
HIGH_WATERMARK,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_LEVEL_BUFFERS,
|
||||
ARG_LEVEL_BYTES,
|
||||
ARG_LEVEL_TIME,
|
||||
ARG_SIZE_BUFFERS,
|
||||
ARG_SIZE_BYTES,
|
||||
ARG_SIZE_TIME,
|
||||
ARG_LEAKY,
|
||||
ARG_LEVEL,
|
||||
ARG_MAX_LEVEL,
|
||||
ARG_BLOCK,
|
||||
};
|
||||
|
||||
|
||||
|
@ -77,6 +85,23 @@ static void gst_queue_flush (GstQueue *queue);
|
|||
static GstElementStateReturn gst_queue_change_state (GstElement *element);
|
||||
|
||||
|
||||
static GtkType
|
||||
queue_leaky_get_type(void) {
|
||||
static GtkType queue_leaky_type = 0;
|
||||
static GtkEnumValue queue_leaky[] = {
|
||||
{ GST_QUEUE_NO_LEAK, "0", "Not Leaky" },
|
||||
{ GST_QUEUE_LEAK_UPSTREAM, "1", "Leaky on Upstream" },
|
||||
{ GST_QUEUE_LEAK_DOWNSTREAM, "2", "Leaky on Downstream" },
|
||||
{ 0, NULL, NULL },
|
||||
};
|
||||
if (!queue_leaky_type) {
|
||||
queue_leaky_type = gtk_type_register_enum("GstQueueLeaky", queue_leaky);
|
||||
}
|
||||
return queue_leaky_type;
|
||||
}
|
||||
#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type())
|
||||
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
//static guint gst_queue_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
@ -111,12 +136,12 @@ gst_queue_class_init (GstQueueClass *klass)
|
|||
|
||||
parent_class = gtk_type_class (GST_TYPE_ELEMENT);
|
||||
|
||||
gtk_object_add_arg_type ("GstQueue::leaky", GST_TYPE_QUEUE_LEAKY,
|
||||
GTK_ARG_READWRITE, ARG_LEAKY);
|
||||
gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT,
|
||||
GTK_ARG_READABLE, ARG_LEVEL);
|
||||
gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT,
|
||||
GTK_ARG_READWRITE, ARG_MAX_LEVEL);
|
||||
gtk_object_add_arg_type ("GstQueue::block", GTK_TYPE_BOOL,
|
||||
GTK_ARG_READWRITE, ARG_BLOCK);
|
||||
|
||||
gtkobject_class->set_arg = gst_queue_set_arg;
|
||||
gtkobject_class->get_arg = gst_queue_get_arg;
|
||||
|
@ -144,14 +169,15 @@ gst_queue_init (GstQueue *queue)
|
|||
|
||||
queue->queue = NULL;
|
||||
queue->level_buffers = 0;
|
||||
queue->max_buffers = 100;
|
||||
queue->block = TRUE;
|
||||
queue->level_bytes = 0;
|
||||
queue->size_buffers = 0;
|
||||
queue->size_bytes = 0;
|
||||
queue->level_time = 0LL;
|
||||
queue->size_buffers = 100; // 100 buffers
|
||||
queue->size_bytes = 100 * 1024; // 100KB
|
||||
queue->size_time = 1000000000LL; // 1sec
|
||||
|
||||
queue->emptycond = g_cond_new ();
|
||||
queue->fullcond = g_cond_new ();
|
||||
GST_DEBUG(GST_CAT_THREAD, "initialized queue's emptycond and fullcond\n");
|
||||
}
|
||||
|
||||
static GstBufferPool*
|
||||
|
@ -206,10 +232,10 @@ gst_queue_handle_eos (GstPad *pad)
|
|||
|
||||
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
|
||||
|
||||
GST_DEBUG (0,"queue: %s received eos\n", GST_ELEMENT_NAME (queue));
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s received eos\n", GST_ELEMENT_NAME (queue));
|
||||
|
||||
GST_LOCK (queue);
|
||||
GST_DEBUG (0,"queue: %s has %d buffers left\n", GST_ELEMENT_NAME (queue),
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s has %d buffers left\n", GST_ELEMENT_NAME (queue),
|
||||
queue->level_buffers);
|
||||
|
||||
GST_FLAG_SET (pad, GST_PAD_EOS);
|
||||
|
@ -224,7 +250,7 @@ gst_queue_handle_eos (GstPad *pad)
|
|||
static void
|
||||
gst_queue_cleanup_buffers (gpointer data, const gpointer user_data)
|
||||
{
|
||||
GST_DEBUG (0,"queue: %s cleaning buffer %p\n", (gchar *)user_data, data);
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s cleaning buffer %p\n", (gchar *)user_data, data);
|
||||
|
||||
gst_buffer_unref (GST_BUFFER (data));
|
||||
}
|
||||
|
@ -257,45 +283,79 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf)
|
|||
|
||||
/* we have to lock the queue since we span threads */
|
||||
|
||||
GST_DEBUG (0,"queue: try have queue lock\n");
|
||||
// GST_DEBUG (GST_CAT_DATAFLOW,"trying to get lock on queue \"%s\"\n",name);
|
||||
GST_LOCK (queue);
|
||||
GST_DEBUG (0,"queue: %s adding buffer %p %ld\n", name, buf, pthread_self ());
|
||||
GST_DEBUG (0,"queue: have queue lock\n");
|
||||
|
||||
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) {
|
||||
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "buffer has FLUSH bit set, flushing queue\n");
|
||||
gst_queue_flush (queue);
|
||||
}
|
||||
|
||||
GST_DEBUG (0,"queue: %s: chain %d %p\n", name, queue->level_buffers, buf);
|
||||
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "adding buffer %p of size %d\n",buf,GST_BUFFER_SIZE(buf));
|
||||
|
||||
while (queue->level_buffers >= queue->max_buffers) {
|
||||
GST_DEBUG (0,"queue: %s waiting %d\n", name, queue->level_buffers);
|
||||
STATUS("%s: O\n");
|
||||
//g_cond_timed_wait (queue->fullcond, queue->fulllock, queue->timeval);
|
||||
//FIXME need to signal other thread in case signals got lost?
|
||||
if (queue->level_buffers >= queue->size_buffers) {
|
||||
// if this is a leaky queue...
|
||||
if (queue->leaky) {
|
||||
// if we leak on the upstream side, drop the current buffer
|
||||
if (queue->leaky == GST_QUEUE_LEAK_UPSTREAM) {
|
||||
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on upstream end\n");
|
||||
gst_buffer_unref(buf);
|
||||
// now we have to clean up and exit right away
|
||||
GST_UNLOCK (queue);
|
||||
return;
|
||||
}
|
||||
// otherwise we have to push a buffer off the other end
|
||||
else {
|
||||
GSList *front;
|
||||
GstBuffer *leakbuf;
|
||||
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end\n");
|
||||
front = queue->queue;
|
||||
leakbuf = (GstBuffer *)(front->data);
|
||||
queue->level_buffers--;
|
||||
queue->level_bytes -= GST_BUFFER_SIZE(leakbuf);
|
||||
gst_buffer_unref(leakbuf);
|
||||
queue->queue = g_slist_remove_link (queue->queue, front);
|
||||
g_slist_free (front);
|
||||
}
|
||||
}
|
||||
|
||||
while (queue->level_buffers >= queue->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);
|
||||
STATUS("%s: O+\n");
|
||||
GST_DEBUG (0,"queue: %s waiting done %d\n", name, queue->level_buffers);
|
||||
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "done waiting, level is now %d\n", queue->level_buffers);
|
||||
}
|
||||
}
|
||||
|
||||
/* put the buffer on the tail of the list */
|
||||
queue->queue = g_slist_append (queue->queue, buf);
|
||||
// STATUS("%s: +\n");
|
||||
GST_DEBUG (0,"(%s:%s)+ ",GST_DEBUG_PAD_NAME(pad));
|
||||
queue->level_buffers++;
|
||||
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 */
|
||||
tosignal = (queue->level_buffers >= 0);
|
||||
queue->level_buffers++;
|
||||
|
||||
/* we can unlock now */
|
||||
GST_DEBUG (0,"queue: %s chain %d end signal(%d,%p)\n", name, queue->level_buffers, tosignal, queue->emptycond);
|
||||
|
||||
if (tosignal) {
|
||||
// STATUS("%s: >\n");
|
||||
if (queue->level_buffers == 1)
|
||||
{
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling emptycond\n", name);
|
||||
g_cond_signal (queue->emptycond);
|
||||
// STATUS("%s: >>\n");
|
||||
}
|
||||
|
||||
GST_UNLOCK (queue);
|
||||
}
|
||||
|
||||
|
@ -307,6 +367,8 @@ gst_queue_get (GstPad *pad)
|
|||
GSList *front;
|
||||
const guchar *name;
|
||||
|
||||
g_assert(pad != NULL);
|
||||
g_assert(GST_IS_PAD(pad));
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||
|
||||
|
@ -314,63 +376,74 @@ gst_queue_get (GstPad *pad)
|
|||
name = GST_ELEMENT_NAME (queue);
|
||||
|
||||
/* have to lock for thread-safety */
|
||||
GST_DEBUG (0,"queue: %s try have queue lock\n", name);
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s try have queue lock\n", name);
|
||||
GST_LOCK (queue);
|
||||
GST_DEBUG (0,"queue: %s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
|
||||
GST_DEBUG (0,"queue: %s have queue lock\n", name);
|
||||
|
||||
// we bail if there's nothing there
|
||||
if (!queue->level_buffers && !queue->block) {
|
||||
GST_UNLOCK(queue);
|
||||
return NULL;
|
||||
}
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s have queue lock\n", name);
|
||||
|
||||
while (!queue->level_buffers) {
|
||||
STATUS("queue: %s U released lock\n");
|
||||
//g_cond_timed_wait (queue->emptycond, queue->emptylock, queue->timeval);
|
||||
if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) {
|
||||
GST_DEBUG (GST_CAT_DATAFLOW, "%s U released lock\n", name);
|
||||
GST_UNLOCK(queue);
|
||||
gst_pad_set_eos (queue->srcpad);
|
||||
// this return NULL shouldn't hurt anything...
|
||||
return NULL;
|
||||
}
|
||||
//FIXME need to signal other thread in case signals got lost?
|
||||
|
||||
// if there's a pending state change for this queue or its manager, switch
|
||||
// back to iterator so bottom half of state change executes
|
||||
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
|
||||
// GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
|
||||
GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->srcpad))))) !=
|
||||
GST_STATE_NONE_PENDING)
|
||||
{
|
||||
GST_DEBUG(GST_CAT_DATAFLOW,"interrupted!!\n");
|
||||
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)
|
||||
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)\n");
|
||||
if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
|
||||
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING\n");
|
||||
GST_UNLOCK(queue);
|
||||
cothread_switch(cothread_current_main());
|
||||
}
|
||||
|
||||
g_cond_signal (queue->fullcond);
|
||||
g_cond_wait (queue->emptycond, GST_OBJECT(queue)->lock);
|
||||
// STATUS("queue: %s U- getting lock\n");
|
||||
}
|
||||
|
||||
front = queue->queue;
|
||||
buf = (GstBuffer *)(front->data);
|
||||
GST_DEBUG (0,"retrieved buffer %p from queue\n",buf);
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"retrieved buffer %p from queue\n",buf);
|
||||
queue->queue = g_slist_remove_link (queue->queue, front);
|
||||
g_slist_free (front);
|
||||
|
||||
queue->level_buffers--;
|
||||
// STATUS("%s: -\n");
|
||||
GST_DEBUG (0,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
|
||||
|
||||
if (queue->level_buffers < queue->max_buffers) {
|
||||
// STATUS("%s: < \n");
|
||||
// if (queue->level_buffers < queue->size_buffers)
|
||||
if (queue->level_buffers == queue->size_buffers)
|
||||
{
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling fullcond\n", name);
|
||||
g_cond_signal (queue->fullcond);
|
||||
// STATUS("%s: << \n");
|
||||
}
|
||||
|
||||
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_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;
|
||||
/* unlock now */
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_queue_change_state (GstElement *element)
|
||||
{
|
||||
GstQueue *queue;
|
||||
GstElementStateReturn ret;
|
||||
g_return_val_if_fail (GST_IS_QUEUE (element), GST_STATE_FAILURE);
|
||||
|
||||
queue = GST_QUEUE (element);
|
||||
GST_DEBUG (0,"gstqueue: state pending %d\n", GST_STATE_PENDING (element));
|
||||
|
||||
// lock the queue so another thread (not in sync with this thread's state)
|
||||
// can't call this queue's _get (or whatever)
|
||||
GST_LOCK (queue);
|
||||
|
||||
/* if going down into NULL state, clear out buffers*/
|
||||
if (GST_STATE_PENDING (element) == GST_STATE_READY) {
|
||||
|
@ -380,9 +453,41 @@ gst_queue_change_state (GstElement *element)
|
|||
|
||||
/* if we haven't failed already, give the parent class a chance to ;-) */
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
{
|
||||
gboolean valid_handler = FALSE;
|
||||
guint state_change_id = gtk_signal_lookup("state_change", GTK_OBJECT_TYPE(element));
|
||||
|
||||
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);
|
||||
|
||||
switch(id) {
|
||||
case ARG_MAX_LEVEL:
|
||||
queue->max_buffers = GTK_VALUE_INT (*arg);
|
||||
case ARG_LEAKY:
|
||||
queue->leaky = GTK_VALUE_INT (*arg);
|
||||
break;
|
||||
case ARG_BLOCK:
|
||||
queue->block = GTK_VALUE_BOOL (*arg);
|
||||
case ARG_MAX_LEVEL:
|
||||
queue->size_buffers = GTK_VALUE_INT (*arg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -419,14 +524,14 @@ gst_queue_get_arg (GtkObject *object, GtkArg *arg, guint id)
|
|||
queue = GST_QUEUE (object);
|
||||
|
||||
switch (id) {
|
||||
case ARG_LEAKY:
|
||||
GTK_VALUE_INT (*arg) = queue->leaky;
|
||||
break;
|
||||
case ARG_LEVEL:
|
||||
GTK_VALUE_INT (*arg) = queue->level_buffers;
|
||||
break;
|
||||
case ARG_MAX_LEVEL:
|
||||
GTK_VALUE_INT (*arg) = queue->max_buffers;
|
||||
break;
|
||||
case ARG_BLOCK:
|
||||
GTK_VALUE_BOOL (*arg) = queue->block;
|
||||
GTK_VALUE_INT (*arg) = queue->size_buffers;
|
||||
break;
|
||||
default:
|
||||
arg->type = GTK_TYPE_INVALID;
|
||||
|
|
|
@ -47,6 +47,12 @@ GstElementDetails gst_queue_details;
|
|||
#define GST_IS_QUEUE_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
|
||||
|
||||
enum {
|
||||
GST_QUEUE_NO_LEAK = 0,
|
||||
GST_QUEUE_LEAK_UPSTREAM = 1,
|
||||
GST_QUEUE_LEAK_DOWNSTREAM = 2
|
||||
};
|
||||
|
||||
typedef struct _GstQueue GstQueue;
|
||||
typedef struct _GstQueueClass GstQueueClass;
|
||||
|
||||
|
@ -60,12 +66,16 @@ struct _GstQueue {
|
|||
GSList *queue;
|
||||
|
||||
gint level_buffers; /* number of buffers queued here */
|
||||
gint max_buffers; /* maximum number of buffers queued here */
|
||||
gboolean block; /* if set to FALSE, _get returns NULL if queue empty */
|
||||
gint level_bytes; /* number of bytes queued here */
|
||||
guint64 level_time; /* amount of time queued here */
|
||||
|
||||
gint size_buffers; /* size of queue in buffers */
|
||||
gint size_bytes; /* size of queue in bytes */
|
||||
guint64 size_time; /* size of queue in time */
|
||||
|
||||
gint leaky; /* whether the queue is leaky, and if so at which end */
|
||||
|
||||
// GMutex *lock; (optimization?)
|
||||
GCond *emptycond;
|
||||
GCond *fullcond;
|
||||
|
||||
|
@ -74,6 +84,10 @@ struct _GstQueue {
|
|||
|
||||
struct _GstQueueClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
/* signal callbacks */
|
||||
void (*low_watermark) (GstQueue *queue, gint level);
|
||||
void (*high_watermark) (GstQueue *queue, gint level);
|
||||
};
|
||||
|
||||
GtkType gst_queue_get_type (void);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,6 +24,7 @@
|
|||
#ifndef __GST_SCHEDULER_H__
|
||||
#define __GST_SCHEDULER_H__
|
||||
|
||||
#include <gst/gstelement.h>
|
||||
#include <gst/gstbin.h>
|
||||
|
||||
|
||||
|
@ -32,8 +33,106 @@ extern "C" {
|
|||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#define GST_TYPE_SCHEDULE \
|
||||
(gst_schedule_get_type())
|
||||
#define GST_SCHEDULE(obj) \
|
||||
(GTK_CHECK_CAST((obj),GST_TYPE_SCHEDULE,GstSchedule))
|
||||
#define GST_SCHEDULE_CLASS(klass) \
|
||||
(GTK_CHECK_CLASS_CAST((klass),GST_TYPE_SCHEDULE,GstScheduleClass))
|
||||
#define GST_IS_SCHEDULE(obj) \
|
||||
(GTK_CHECK_TYPE((obj),GST_TYPE_SCHEDULE))
|
||||
#define GST_IS_SCHEDULE_CLASS(klass) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_SCHEDULE))
|
||||
|
||||
|
||||
#define GST_SCHED_PARENT(sched) ((sched)->parent)
|
||||
|
||||
//typedef struct _GstSchedule GstSchedule;
|
||||
//typedef struct _GstScheduleClass GstScheduleClass;
|
||||
typedef struct _GstScheduleChain GstScheduleChain;
|
||||
|
||||
struct _GstSchedule {
|
||||
GstObject object;
|
||||
|
||||
GstElement *parent;
|
||||
|
||||
GList *elements;
|
||||
gint num_elements;
|
||||
|
||||
GList *chains;
|
||||
gint num_chains;
|
||||
|
||||
void (*add_element) (GstSchedule *sched, GstElement *element);
|
||||
void (*remove_element) (GstSchedule *sched, GstElement *element);
|
||||
void (*enable_element) (GstSchedule *sched, GstElement *element);
|
||||
void (*disable_element) (GstSchedule *sched, GstElement *element);
|
||||
void (*lock_element) (GstSchedule *sched, GstElement *element);
|
||||
void (*unlock_element) (GstSchedule *sched, GstElement *element);
|
||||
void (*pad_connect) (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
|
||||
void (*pad_disconnect) (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
|
||||
gboolean (*iterate) (GstSchedule *sched);
|
||||
};
|
||||
|
||||
struct _GstScheduleClass {
|
||||
GstObjectClass parent_class;
|
||||
};
|
||||
|
||||
//#define GST_SCHEDULE_SAFETY if (sched)
|
||||
#define GST_SCHEDULE_SAFETY
|
||||
|
||||
#define GST_SCHEDULE_ADD_ELEMENT(sched,element) \
|
||||
GST_SCHEDULE_SAFETY ((sched)->add_element((sched),(element)))
|
||||
#define GST_SCHEDULE_REMOVE_ELEMENT(sched,element) \
|
||||
GST_SCHEDULE_SAFETY ((sched)->remove_element((sched),(element)))
|
||||
#define GST_SCHEDULE_ENABLE_ELEMENT(sched,element) \
|
||||
GST_SCHEDULE_SAFETY ((sched)->enable_element((sched),(element)))
|
||||
#define GST_SCHEDULE_DISABLE_ELEMENT(sched,element) \
|
||||
GST_SCHEDULE_SAFETY ((sched)->disable_element((sched),(element)))
|
||||
#define GST_SCHEDULE_LOCK_ELEMENT(sched,element) \
|
||||
GST_SCHEDULE_SAFETY if ((sched)->lock_element != NULL) \
|
||||
((sched)->lock_element((sched),(element)))
|
||||
#define GST_SCHEDULE_UNLOCK_ELEMENT(sched,element) \
|
||||
GST_SCHEDULE_SAFETY if ((sched)->unlock_element != NULL) \
|
||||
((sched)->unlock_element((sched),(element)))
|
||||
#define GST_SCHEDULE_PAD_CONNECT(sched,srcpad,sinkpad) \
|
||||
GST_SCHEDULE_SAFETY ((sched)->pad_connect((sched),(srcpad),(sinkpad)))
|
||||
#define GST_SCHEDULE_PAD_DISCONNECT(sched,srcpad,sinkpad) \
|
||||
GST_SCHEDULE_SAFETY ((sched)->pad_disconnect((sched),(srcpad),(sinkpad)))
|
||||
#define GST_SCHEDULE_ITERATE(sched) \
|
||||
((sched)->iterate((sched)))
|
||||
|
||||
|
||||
|
||||
struct _GstScheduleChain {
|
||||
GstSchedule *sched;
|
||||
|
||||
GList *disabled;
|
||||
|
||||
GList *elements;
|
||||
gint num_elements;
|
||||
|
||||
GstElement *entry;
|
||||
|
||||
gint cothreaded_elements;
|
||||
gboolean schedule;
|
||||
};
|
||||
|
||||
|
||||
void gst_bin_schedule_func(GstBin *bin);
|
||||
|
||||
GtkType gst_schedule_get_type (void);
|
||||
GstSchedule * gst_schedule_new (GstElement *parent);
|
||||
|
||||
void gst_schedule_add_element (GstSchedule *sched, GstElement *element);
|
||||
void gst_schedule_remove_element (GstSchedule *sched, GstElement *element);
|
||||
void gst_schedule_enable_element (GstSchedule *sched, GstElement *element);
|
||||
void gst_schedule_disable_element (GstSchedule *sched, GstElement *element);
|
||||
void gst_schedule_pad_connect (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
|
||||
void gst_schedule_pad_disconnect (GstSchedule *sched, GstPad *srcpad, GstPad *sinkpad);
|
||||
gboolean gst_schedule_iterate (GstSchedule *sched);
|
||||
|
||||
void gst_schedule_show (GstSchedule *sched);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
460
gst/gstthread.c
460
gst/gstthread.c
|
@ -26,7 +26,8 @@
|
|||
#include "gst_private.h"
|
||||
|
||||
#include "gstthread.h"
|
||||
|
||||
#include "gstscheduler.h"
|
||||
#include "gstqueue.h"
|
||||
|
||||
GstElementDetails gst_thread_details = {
|
||||
"Threaded container",
|
||||
|
@ -44,15 +45,24 @@ enum {
|
|||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
SPINUP=0,
|
||||
STATECHANGE,
|
||||
STARTUP
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_CREATE_THREAD,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void gst_thread_class_init (GstThreadClass *klass);
|
||||
static void gst_thread_init (GstThread *thread);
|
||||
|
||||
static void gst_thread_real_destroy (GtkObject *gtk_object);
|
||||
|
||||
static void gst_thread_set_arg (GtkObject *object, GtkArg *arg, guint id);
|
||||
static void gst_thread_get_arg (GtkObject *object, GtkArg *arg, guint id);
|
||||
|
||||
|
@ -61,9 +71,7 @@ static GstElementStateReturn gst_thread_change_state (GstElement *element);
|
|||
static xmlNodePtr gst_thread_save_thyself (GstObject *object, xmlNodePtr parent);
|
||||
static void gst_thread_restore_thyself (GstObject *object, xmlNodePtr self);
|
||||
|
||||
static void gst_thread_signal_thread (GstThread *thread);
|
||||
static void gst_thread_wait_thread (GstThread *thread);
|
||||
static void gst_thread_schedule_dummy (GstBin *bin);
|
||||
static void gst_thread_signal_thread (GstThread *thread, gboolean spinning);
|
||||
|
||||
static void* gst_thread_main_loop (void *arg);
|
||||
|
||||
|
@ -108,12 +116,14 @@ gst_thread_class_init (GstThreadClass *klass)
|
|||
gtk_object_add_arg_type ("GstThread::create_thread", GTK_TYPE_BOOL,
|
||||
GTK_ARG_READWRITE, ARG_CREATE_THREAD);
|
||||
|
||||
gtkobject_class->destroy = gst_thread_real_destroy;
|
||||
|
||||
gstobject_class->save_thyself = gst_thread_save_thyself;
|
||||
gstobject_class->restore_thyself = gst_thread_restore_thyself;
|
||||
|
||||
gstelement_class->change_state = gst_thread_change_state;
|
||||
|
||||
gstbin_class->schedule = gst_thread_schedule_dummy;
|
||||
// gstbin_class->schedule = gst_thread_schedule_dummy;
|
||||
|
||||
gtkobject_class->set_arg = gst_thread_set_arg;
|
||||
gtkobject_class->get_arg = gst_thread_get_arg;
|
||||
|
@ -123,26 +133,41 @@ gst_thread_class_init (GstThreadClass *klass)
|
|||
static void
|
||||
gst_thread_init (GstThread *thread)
|
||||
{
|
||||
GST_DEBUG (0,"initializing thread '%s'\n",GST_ELEMENT_NAME (thread));
|
||||
|
||||
GST_DEBUG (GST_CAT_THREAD,"initializing thread\n");
|
||||
|
||||
// we're a manager by default
|
||||
GST_FLAG_SET (thread, GST_BIN_FLAG_MANAGER);
|
||||
|
||||
// default is to create a thread
|
||||
GST_FLAG_SET (thread, GST_THREAD_CREATE);
|
||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
|
||||
|
||||
thread->lock = g_mutex_new();
|
||||
thread->cond = g_cond_new();
|
||||
|
||||
GST_ELEMENT_SCHED(thread) = gst_schedule_new(GST_ELEMENT(thread));
|
||||
GST_DEBUG(GST_CAT_THREAD, "thread's scheduler is %p\n",GST_ELEMENT_SCHED(thread));
|
||||
|
||||
thread->ppid = getpid();
|
||||
|
||||
// gst_element_set_manager(GST_ELEMENT(thread),GST_ELEMENT(thread));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_thread_schedule_dummy (GstBin *bin)
|
||||
gst_thread_real_destroy (GtkObject *gtk_object)
|
||||
{
|
||||
g_return_if_fail (GST_IS_THREAD (bin));
|
||||
GstThread *thread = GST_THREAD (gtk_object);
|
||||
|
||||
if (!GST_FLAG_IS_SET (GST_THREAD (bin), GST_THREAD_STATE_SPINNING))
|
||||
GST_INFO (GST_CAT_THREAD,"gstthread: scheduling delayed until thread starts");
|
||||
GST_DEBUG (GST_CAT_REFCOUNTING,"destroy()\n");
|
||||
|
||||
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
|
||||
|
@ -156,13 +181,13 @@ gst_thread_set_arg (GtkObject *object,
|
|||
switch(id) {
|
||||
case ARG_CREATE_THREAD:
|
||||
if (GTK_VALUE_BOOL (*arg)) {
|
||||
GST_INFO (GST_CAT_THREAD,"gstthread: turning ON the creation of the thread");
|
||||
GST_INFO (GST_CAT_THREAD,"turning ON the creation of the thread");
|
||||
GST_FLAG_SET (object, GST_THREAD_CREATE);
|
||||
GST_DEBUG (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
|
||||
// GST_DEBUG (GST_CAT_THREAD,"flags are 0x%08x\n", GST_FLAGS (object));
|
||||
} else {
|
||||
GST_INFO (GST_CAT_THREAD,"gstthread: turning OFF the creation of the thread");
|
||||
GST_FLAG_UNSET (object, GST_THREAD_CREATE);
|
||||
GST_DEBUG (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
|
||||
// GST_DEBUG (GST_CAT_THREAD,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -197,95 +222,237 @@ gst_thread_get_arg (GtkObject *object,
|
|||
* Returns: The new thread
|
||||
*/
|
||||
GstElement*
|
||||
gst_thread_new (guchar *name)
|
||||
gst_thread_new (const guchar *name)
|
||||
{
|
||||
return gst_elementfactory_make ("thread", name);
|
||||
}
|
||||
|
||||
|
||||
#define THR_INFO(format,args...) \
|
||||
GST_INFO_ELEMENT(GST_CAT_THREAD, thread, "sync(" GST_DEBUG_THREAD_FORMAT "): " format , \
|
||||
GST_DEBUG_THREAD_ARGS(thread->pid) , ## args )
|
||||
#define THR_DEBUG(format,args...) \
|
||||
GST_DEBUG_ELEMENT(GST_CAT_THREAD, thread, "sync(" GST_DEBUG_THREAD_FORMAT "): " format , \
|
||||
GST_DEBUG_THREAD_ARGS(thread->pid) , ## args )
|
||||
|
||||
#define THR_INFO_MAIN(format,args...) \
|
||||
GST_INFO_ELEMENT(GST_CAT_THREAD, thread, "sync-main(" GST_DEBUG_THREAD_FORMAT "): " format , \
|
||||
GST_DEBUG_THREAD_ARGS(thread->ppid) , ## args )
|
||||
#define THR_DEBUG_MAIN(format,args...) \
|
||||
GST_DEBUG_ELEMENT(GST_CAT_THREAD, thread, "sync-main(" GST_DEBUG_THREAD_FORMAT "): " format , \
|
||||
GST_DEBUG_THREAD_ARGS(thread->ppid) , ## args )
|
||||
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_thread_change_state (GstElement *element)
|
||||
{
|
||||
GstThread *thread;
|
||||
gboolean stateset = GST_STATE_SUCCESS;
|
||||
gint pending, transition;
|
||||
gint transition;
|
||||
pthread_t self = pthread_self();
|
||||
GstElement *peerelement;
|
||||
|
||||
g_return_val_if_fail (GST_IS_THREAD(element), FALSE);
|
||||
GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME(element));
|
||||
// GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME(element));
|
||||
|
||||
thread = GST_THREAD (element);
|
||||
// GST_DEBUG (GST_CAT_THREAD, "**** THREAD %ld changing THREAD %ld ****\n",self,thread->thread_id);
|
||||
// GST_DEBUG (GST_CAT_THREAD, "**** current pid=%d\n",getpid());
|
||||
|
||||
GST_INFO (GST_CAT_THREAD,"gstthread: thread \"%s\" change state %d",
|
||||
GST_ELEMENT_NAME (GST_ELEMENT (element)),
|
||||
GST_STATE_PENDING (element));
|
||||
|
||||
pending = GST_STATE_PENDING (element);
|
||||
transition = GST_STATE_TRANSITION (element);
|
||||
|
||||
// if (pending == GST_STATE (element)) return GST_STATE_SUCCESS;
|
||||
THR_INFO("changing state from %s to %s",
|
||||
gst_element_statename(GST_STATE (element)),
|
||||
gst_element_statename(GST_STATE_PENDING (element)));
|
||||
|
||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
stateset = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
GST_INFO (GST_CAT_THREAD, "gstthread: stateset %d %d %d %02x", GST_STATE (element), stateset,
|
||||
GST_STATE_PENDING (element), GST_STATE_TRANSITION (element));
|
||||
//GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
// if (!stateset) return FALSE;
|
||||
// we want to prepare our internal state for doing the iterations
|
||||
GST_INFO (GST_CAT_THREAD, "gstthread: preparing thread \"%s\" for iterations:",
|
||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||
|
||||
// set the state to idle
|
||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||
// create the thread if that's what we're supposed to do
|
||||
GST_INFO (GST_CAT_THREAD, "gstthread: flags are 0x%08x", GST_FLAGS (thread));
|
||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
|
||||
|
||||
// create the thread if that's what we're supposed to do
|
||||
if (GST_FLAG_IS_SET (thread, GST_THREAD_CREATE)) {
|
||||
GST_INFO (GST_CAT_THREAD, "gstthread: starting thread \"%s\"",
|
||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||
THR_DEBUG ("creating thread \"%s\"\n",
|
||||
GST_ELEMENT_NAME (element));
|
||||
|
||||
g_mutex_lock (thread->lock);
|
||||
|
||||
// create the thread
|
||||
pthread_create (&thread->thread_id, NULL,
|
||||
gst_thread_main_loop, thread);
|
||||
|
||||
// wait for it to 'spin up'
|
||||
//gst_thread_wait_thread (thread);
|
||||
THR_DEBUG("waiting for child thread spinup\n");
|
||||
g_cond_wait(thread->cond,thread->lock);
|
||||
THR_DEBUG("thread claims to be up\n");
|
||||
g_mutex_unlock(thread->lock);
|
||||
} else {
|
||||
GST_INFO (GST_CAT_THREAD, "gstthread: NOT starting thread \"%s\"",
|
||||
GST_INFO (GST_CAT_THREAD, "NOT creating thread \"%s\"",
|
||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||
|
||||
// punt and change state on all the children
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
stateset = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
}
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
THR_INFO("readying thread");
|
||||
|
||||
// check to see if the thread is somehow changing its own state.
|
||||
// FIXME this is currently illegal, but must somehow be made legal at some point.
|
||||
if (pthread_equal(self, thread->thread_id))
|
||||
{
|
||||
//FIXME this should not happen
|
||||
g_assert(!pthread_equal(self, thread->thread_id));
|
||||
GST_FLAG_SET(thread, GST_THREAD_STATE_SPINNING);
|
||||
GST_DEBUG(GST_CAT_THREAD,"no sync(" GST_DEBUG_THREAD_FORMAT "): setting own thread's state to spinning\n",
|
||||
GST_DEBUG_THREAD_ARGS(thread->pid));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_mutex_lock(thread->lock);
|
||||
gst_thread_signal_thread(thread,FALSE);
|
||||
}
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
case GST_STATE_READY_TO_PLAYING:
|
||||
if (!stateset) return FALSE;
|
||||
GST_INFO (GST_CAT_THREAD, "gstthread: starting thread \"%s\"",
|
||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||
THR_INFO("starting thread");
|
||||
|
||||
// check to see if the thread is somehow changing its own state.
|
||||
// FIXME this is currently illegal, but must somehow be made legal at some point.
|
||||
if (pthread_equal(self, thread->thread_id))
|
||||
{
|
||||
//FIXME this should not happen
|
||||
g_assert(!pthread_equal(self, thread->thread_id));
|
||||
GST_FLAG_SET(thread, GST_THREAD_STATE_SPINNING);
|
||||
gst_thread_signal_thread (thread);
|
||||
GST_DEBUG(GST_CAT_THREAD,"no sync(" GST_DEBUG_THREAD_FORMAT "): setting own thread's state to spinning\n",
|
||||
GST_DEBUG_THREAD_ARGS(thread->pid));
|
||||
}
|
||||
else
|
||||
{
|
||||
THR_DEBUG("telling thread to start spinning\n");
|
||||
g_mutex_lock(thread->lock);
|
||||
gst_thread_signal_thread(thread,TRUE);
|
||||
}
|
||||
break;
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
GST_INFO (GST_CAT_THREAD,"gstthread: pausing thread \"%s\"",
|
||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||
THR_INFO("pausing thread");
|
||||
|
||||
//GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
|
||||
gst_thread_signal_thread (thread);
|
||||
// check to see if the thread is somehow changing its own state.
|
||||
// FIXME this is currently illegal, but must somehow be made legal at some point.
|
||||
if (pthread_equal(self, thread->thread_id))
|
||||
{
|
||||
//FIXME this should not happen
|
||||
GST_DEBUG(GST_CAT_THREAD,"no sync(" GST_DEBUG_THREAD_FORMAT "): setting own thread's state to paused\n",
|
||||
GST_DEBUG_THREAD_ARGS(thread->pid));
|
||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||
g_assert(!pthread_equal(self, thread->thread_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
GList *elements = (element->sched)->elements;
|
||||
|
||||
// the following code ensures that the bottom half of thread will run
|
||||
// to perform each elements' change_state() (by calling gstbin.c::
|
||||
// change_state()).
|
||||
// + the pending state was already set by gstelement.c::set_state()
|
||||
// + find every queue we manage, and signal its empty and full conditions
|
||||
|
||||
g_mutex_lock(thread->lock);
|
||||
|
||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||
|
||||
while (elements)
|
||||
{
|
||||
GstElement *e = GST_ELEMENT(elements->data);
|
||||
g_assert(e);
|
||||
THR_DEBUG(" element \"%s\"\n",GST_ELEMENT_NAME(e));
|
||||
elements = g_list_next(elements);
|
||||
if (GST_IS_QUEUE(e))
|
||||
{
|
||||
//FIXME make this more efficient by only waking queues that are asleep
|
||||
//FIXME and only waking the appropriate condition (depending on if it's
|
||||
//FIXME on up- or down-stream side)
|
||||
//
|
||||
//FIXME also make this more efficient by keeping list of managed queues
|
||||
THR_DEBUG("waking queue \"%s\"\n",GST_ELEMENT_NAME(e));
|
||||
GST_LOCK(e);
|
||||
g_cond_signal((GST_QUEUE(e)->emptycond));
|
||||
g_cond_signal((GST_QUEUE(e)->fullcond));
|
||||
GST_UNLOCK(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
GList *pads = GST_ELEMENT_PADS(e);
|
||||
while (pads)
|
||||
{
|
||||
GstPad *p = GST_PAD(pads->data);
|
||||
pads = g_list_next(pads);
|
||||
|
||||
peerelement = GST_PAD_PARENT(GST_PAD_PEER(p));
|
||||
if (!peerelement) continue; // deal with case where there's no peer
|
||||
|
||||
if (!GST_FLAG_IS_SET(peerelement,GST_ELEMENT_DECOUPLED)) {
|
||||
GST_DEBUG(GST_CAT_THREAD,"peer element isn't DECOUPLED\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME this needs to go away eventually
|
||||
if (!GST_IS_QUEUE(peerelement)) {
|
||||
GST_DEBUG(GST_CAT_THREAD,"peer element isn't a Queue\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_SCHED(peerelement) != GST_ELEMENT_SCHED(thread))
|
||||
{
|
||||
THR_DEBUG(" element \"%s\" has pad cross sched boundary\n",GST_ELEMENT_NAME(e));
|
||||
GST_LOCK(peerelement);
|
||||
g_cond_signal(GST_QUEUE(peerelement)->emptycond);
|
||||
g_cond_signal(GST_QUEUE(peerelement)->fullcond);
|
||||
GST_UNLOCK(peerelement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
THR_DEBUG("waiting for thread to stop spinning\n");
|
||||
g_cond_wait (thread->cond, thread->lock);
|
||||
THR_DEBUG("telling thread to pause\n");
|
||||
gst_thread_signal_thread(thread,FALSE);
|
||||
}
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
GST_INFO (GST_CAT_THREAD,"gstthread: stopping thread \"%s\"",
|
||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||
THR_INFO("stopping thread");
|
||||
|
||||
GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
|
||||
gst_thread_signal_thread (thread);
|
||||
|
||||
// check to see if the thread is somehow changing its own state.
|
||||
// FIXME this is currently illegal, but must somehow be made legal at some point.
|
||||
if (pthread_equal(self, thread->thread_id))
|
||||
{
|
||||
//FIXME this should not happen
|
||||
g_assert(!pthread_equal(self, thread->thread_id));
|
||||
THR_DEBUG("setting own thread's state to NULL (paused)\n");
|
||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||
}
|
||||
else
|
||||
{
|
||||
THR_DEBUG("telling thread to pause (null) - and joining\n");
|
||||
//MattH FIXME revisit
|
||||
// g_mutex_lock(thread->lock);
|
||||
// gst_thread_signal_thread(thread,FALSE);
|
||||
pthread_join(thread->thread_id,NULL);
|
||||
}
|
||||
|
||||
GST_FLAG_UNSET(thread,GST_THREAD_STATE_REAPING);
|
||||
GST_FLAG_UNSET(thread,GST_THREAD_STATE_STARTED);
|
||||
GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
|
||||
GST_FLAG_UNSET(thread,GST_THREAD_STATE_ELEMENT_CHANGED);
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
stateset = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -294,6 +461,16 @@ gst_thread_change_state (GstElement *element)
|
|||
return stateset;
|
||||
}
|
||||
|
||||
static void gst_thread_update_state (GstThread *thread)
|
||||
{
|
||||
// check for state change
|
||||
if (GST_STATE_PENDING(thread) != GST_STATE_NONE_PENDING) {
|
||||
// punt and change state on all the children
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_thread_main_loop:
|
||||
* @arg: the thread to start
|
||||
|
@ -305,53 +482,186 @@ static void *
|
|||
gst_thread_main_loop (void *arg)
|
||||
{
|
||||
GstThread *thread = GST_THREAD (arg);
|
||||
gint stateset;
|
||||
|
||||
GST_INFO (GST_CAT_THREAD,"gstthread: thread \"%s\" is running with PID %d",
|
||||
GST_ELEMENT_NAME (GST_ELEMENT (thread)), getpid ());
|
||||
thread->pid = getpid();
|
||||
THR_INFO_MAIN("thread is running");
|
||||
|
||||
// first we need to change the state of all the children
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
stateset = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
|
||||
|
||||
// construct the plan and signal back
|
||||
/* DEPRACATED for INCSCHED1
|
||||
THR_DEBUG_MAIN("creating plan for thread\n");
|
||||
if (GST_BIN_CLASS (parent_class)->schedule)
|
||||
GST_BIN_CLASS (parent_class)->schedule (GST_BIN (thread));
|
||||
*/
|
||||
|
||||
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)) {
|
||||
if (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
|
||||
// NOTE we hold the thread lock at this point
|
||||
// what we do depends on what state we're in
|
||||
switch (GST_STATE(thread)) {
|
||||
// NOTE: cannot be in NULL, we're not running in that state at all
|
||||
case GST_STATE_READY:
|
||||
// wait to be set to either the NULL or PAUSED states
|
||||
THR_DEBUG_MAIN("thread in %s state, waiting for either %s or %s\n",
|
||||
gst_element_statename(GST_STATE_READY),
|
||||
gst_element_statename(GST_STATE_NULL),
|
||||
gst_element_statename(GST_STATE_PAUSED));
|
||||
g_cond_wait(thread->cond,thread->lock);
|
||||
// been signaled, we need to state transition now and signal back
|
||||
gst_thread_update_state(thread);
|
||||
THR_DEBUG_MAIN("done with state transition, signaling back to parent process\n");
|
||||
g_cond_signal(thread->cond);
|
||||
// g_mutex_unlock(thread->lock);
|
||||
// now we decide what to do next (FIXME can be collapsed to a continue)
|
||||
if (GST_STATE(thread) == GST_STATE_NULL) {
|
||||
// REAPING must be set, we can simply break this iteration
|
||||
continue;
|
||||
} else {
|
||||
// PAUSED is the next state, we can wait for that next
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case GST_STATE_PAUSED:
|
||||
// wait to be set to either the READY or PLAYING states
|
||||
THR_DEBUG_MAIN("thread in %s state, waiting for either %s or %s\n",
|
||||
gst_element_statename(GST_STATE_PAUSED),
|
||||
gst_element_statename(GST_STATE_READY),
|
||||
gst_element_statename(GST_STATE_PLAYING));
|
||||
g_cond_wait(thread->cond,thread->lock);
|
||||
// been signaled, we need to state transition now and signal back
|
||||
gst_thread_update_state(thread);
|
||||
g_cond_signal(thread->cond);
|
||||
// g_mutex_unlock(thread->lock);
|
||||
// now we decide what to do next
|
||||
if (GST_STATE(thread) == GST_STATE_READY) {
|
||||
// READY is the next state, we can wait for that next
|
||||
continue;
|
||||
} else {
|
||||
g_mutex_unlock(thread->lock);
|
||||
// PLAYING is coming up, so we can now start spinning
|
||||
while (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
|
||||
if (!gst_bin_iterate (GST_BIN (thread))) {
|
||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||
THR_DEBUG_MAIN("removed spinning state due to failed iteration!\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
GST_DEBUG (0, "thread \"%s\" waiting\n", GST_ELEMENT_NAME (GST_ELEMENT (thread)));
|
||||
gst_thread_wait_thread (thread);
|
||||
g_mutex_lock(thread->lock);
|
||||
// once we're here, SPINNING has stopped, we should signal that we're done
|
||||
THR_DEBUG_MAIN("SPINNING stopped, signaling back to parent process\n");
|
||||
g_cond_signal (thread->cond);
|
||||
// now we can wait for PAUSED
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case GST_STATE_PLAYING:
|
||||
// wait to be set to PAUSED
|
||||
THR_DEBUG_MAIN("thread in %s state, waiting for %s\n",
|
||||
gst_element_statename(GST_STATE_PLAYING),
|
||||
gst_element_statename(GST_STATE_PAUSED));
|
||||
g_cond_wait(thread->cond,thread->lock);
|
||||
// been signaled, we need to state transition now and signal back
|
||||
gst_thread_update_state(thread);
|
||||
g_cond_signal(thread->cond);
|
||||
// g_mutex_unlock(thread->lock);
|
||||
// now we decide what to do next
|
||||
// there's only PAUSED, we we just wait for it
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
// need to grab the lock so we're ready for the top of the loop
|
||||
// g_mutex_lock(thread->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) {
|
||||
// start out by waiting for a state change into spinning
|
||||
THR_DEBUG_MAIN("waiting for signal from parent process (at top of while())\n");
|
||||
g_cond_wait (thread->cond,thread->lock);
|
||||
THR_DEBUG_MAIN("woken up with %s pending\n",gst_element_statename(GST_STATE(thread)));
|
||||
// now is a good time to change the state of the children and the thread itself
|
||||
gst_thread_update_state (thread);
|
||||
THR_DEBUG_MAIN("done changing state, signaling back\n");
|
||||
g_cond_signal (thread->cond);
|
||||
g_mutex_unlock (thread->lock);
|
||||
THR_DEBUG_MAIN("finished sycnronizing with main process\n");
|
||||
|
||||
while (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
|
||||
if (!gst_bin_iterate (GST_BIN (thread))) {
|
||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||
THR_DEBUG_MAIN("removed spinning state due to failed iteration!\n");
|
||||
}
|
||||
}
|
||||
|
||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
|
||||
// FIXME this should be removed (why's it here???)
|
||||
// //pthread_join (thread->thread_id, 0);
|
||||
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_ELEMENT_NAME (thread));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// the set flag is to say whether it should set TRUE or FALSE
|
||||
//
|
||||
// WARNING: this has synchronization built in! if you remove or add any
|
||||
// locks, waits, signals, or unlocks you need to be sure they match the
|
||||
// code above (in gst_thread_main_loop()). basically, don't change anything.
|
||||
static void
|
||||
gst_thread_signal_thread (GstThread *thread)
|
||||
gst_thread_signal_thread (GstThread *thread, gboolean spinning)
|
||||
{
|
||||
GST_DEBUG (0,"signaling thread\n");
|
||||
g_mutex_lock (thread->lock);
|
||||
g_cond_signal (thread->cond);
|
||||
g_mutex_unlock (thread->lock);
|
||||
}
|
||||
// set the spinning state
|
||||
if (spinning) GST_FLAG_SET(thread,GST_THREAD_STATE_SPINNING);
|
||||
else GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||
|
||||
static void
|
||||
gst_thread_wait_thread (GstThread *thread)
|
||||
{
|
||||
GST_DEBUG (0,"waiting for thread\n");
|
||||
g_mutex_lock (thread->lock);
|
||||
THR_DEBUG("thread locked\n");
|
||||
// g_mutex_lock(thread->lock);
|
||||
|
||||
// if (!spinning) {
|
||||
// THR_DEBUG("waiting for spindown\n");
|
||||
// g_cond_wait (thread->cond, thread->lock);
|
||||
// }
|
||||
THR_DEBUG("signaling\n");
|
||||
g_cond_signal (thread->cond);
|
||||
THR_DEBUG("waiting for ack\n");
|
||||
g_cond_wait (thread->cond,thread->lock);
|
||||
THR_DEBUG("got ack\n");
|
||||
|
||||
THR_DEBUG("unlocking\n");
|
||||
g_mutex_unlock(thread->lock);
|
||||
THR_DEBUG("unlocked\n");
|
||||
}
|
||||
|
||||
|
||||
|
@ -359,7 +669,7 @@ static void
|
|||
gst_thread_restore_thyself (GstObject *object,
|
||||
xmlNodePtr self)
|
||||
{
|
||||
GST_DEBUG (0,"gstthread: restore\n");
|
||||
GST_DEBUG (GST_CAT_THREAD,"gstthread: restore\n");
|
||||
|
||||
if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
|
||||
GST_OBJECT_CLASS (parent_class)->restore_thyself (object, self);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#ifndef __GST_THREAD_H__
|
||||
#define __GST_THREAD_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <gst/gstbin.h>
|
||||
|
@ -38,8 +39,11 @@ extern GstElementDetails gst_thread_details;
|
|||
|
||||
typedef enum {
|
||||
GST_THREAD_CREATE = GST_BIN_FLAG_LAST,
|
||||
|
||||
GST_THREAD_STATE_STARTED,
|
||||
GST_THREAD_STATE_SPINNING,
|
||||
GST_THREAD_STATE_REAPING,
|
||||
GST_THREAD_STATE_ELEMENT_CHANGED,
|
||||
|
||||
/* padding */
|
||||
GST_THREAD_FLAG_LAST = GST_BIN_FLAG_LAST + 4,
|
||||
|
@ -64,8 +68,12 @@ struct _GstThread {
|
|||
GstBin bin;
|
||||
|
||||
pthread_t thread_id; /* id of the thread, if any */
|
||||
gint pid; /* the pid of the thread */
|
||||
gint ppid; /* the pid of the thread's parent process */
|
||||
GMutex *lock; /* thread lock/condititon pair... */
|
||||
GCond *cond; /* used to control the thread */
|
||||
|
||||
gint transition; /* the current state transition */
|
||||
};
|
||||
|
||||
struct _GstThreadClass {
|
||||
|
@ -74,7 +82,7 @@ struct _GstThreadClass {
|
|||
|
||||
GtkType gst_thread_get_type (void);
|
||||
|
||||
GstElement* gst_thread_new (guchar *name);
|
||||
GstElement* gst_thread_new (const guchar *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ gst_type_register (GstTypeFactory *factory)
|
|||
_gst_types = g_list_prepend (_gst_types, type);
|
||||
|
||||
id = type->id;
|
||||
GST_DEBUG (0,"gsttype: new mime type '%s', id %d\n", type->mime, type->id);
|
||||
GST_DEBUG (GST_CAT_TYPES,"gsttype: new mime type '%s', id %d\n", type->mime, type->id);
|
||||
|
||||
} else {
|
||||
type = gst_type_find_by_id (id);
|
||||
|
@ -108,12 +108,12 @@ guint16 gst_type_find_by_mime_func (const gchar *mime)
|
|||
g_return_val_if_fail (mime != NULL, 0);
|
||||
|
||||
walk = _gst_types;
|
||||
// GST_DEBUG (0,"searching for '%s'\n",mime);
|
||||
// GST_DEBUG (GST_CAT_TYPES,"searching for '%s'\n",mime);
|
||||
mimelen = strlen (mime);
|
||||
while (walk) {
|
||||
type = (GstType *)walk->data;
|
||||
search = type->mime;
|
||||
// GST_DEBUG (0,"checking against '%s'\n",search);
|
||||
// GST_DEBUG (GST_CAT_TYPES,"checking against '%s'\n",search);
|
||||
typelen = strlen (search);
|
||||
while ((search - type->mime) < typelen) {
|
||||
found = strstr (search, mime);
|
||||
|
@ -232,7 +232,7 @@ gst_type_typefind_dummy (GstBuffer *buffer, gpointer priv)
|
|||
guint16 typeid;
|
||||
GSList *funcs;
|
||||
|
||||
GST_DEBUG (0,"gsttype: need to load typefind function for %s\n", type->mime);
|
||||
GST_DEBUG (GST_CAT_TYPES,"gsttype: need to load typefind function for %s\n", type->mime);
|
||||
|
||||
type->typefindfuncs = NULL;
|
||||
gst_plugin_load_typefactory (type->mime);
|
||||
|
|
|
@ -180,11 +180,25 @@ gst_typefind_chain (GstPad *pad, GstBuffer *buf)
|
|||
|
||||
GST_DEBUG (0,"try type :%d \"%s\"\n", type->id, type->mime);
|
||||
if (typefindfunc && (caps = typefindfunc (buf, type))) {
|
||||
GST_DEBUG (0,"found type :%d \"%s\"\n", caps->id, type->mime);
|
||||
GST_DEBUG (0,"found type :%d \"%s\" \"%s\"\n", caps->id, type->mime,
|
||||
gst_caps_get_name (caps));
|
||||
typefind->caps = caps;
|
||||
|
||||
gst_pad_set_caps (pad, caps);
|
||||
|
||||
{ /* FIXME: this should all be in an _emit() wrapper eventually */
|
||||
int oldstate = GST_STATE(typefind);
|
||||
gst_object_ref (GST_OBJECT (typefind));
|
||||
gtk_signal_emit (GTK_OBJECT (typefind), gst_typefind_signals[HAVE_TYPE],
|
||||
typefind->caps);
|
||||
gst_pad_set_caps (pad, caps);
|
||||
if (GST_STATE(typefind) != oldstate) {
|
||||
gst_object_unref (GST_OBJECT (typefind));
|
||||
GST_DEBUG(0, "state changed during signal, aborting\n");
|
||||
cothread_switch(cothread_current_main());
|
||||
}
|
||||
gst_object_unref (GST_OBJECT (typefind));
|
||||
}
|
||||
|
||||
goto end;
|
||||
}
|
||||
funcs = g_slist_next (funcs);
|
||||
|
|
17
gst/gsttypes.h
Normal file
17
gst/gsttypes.h
Normal 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
|
|
@ -167,7 +167,7 @@ gst_xml_parse_doc (GstXML *xml, xmlDocPtr doc, const guchar *root)
|
|||
if (!strcmp(field->name, "element") && (field->ns == xml->ns)) {
|
||||
GstElement *element;
|
||||
|
||||
element = gst_element_load_thyself(field, NULL);
|
||||
element = gst_element_restore_thyself(field, NULL);
|
||||
|
||||
xml->topelements = g_list_prepend (xml->topelements, element);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ noinst_HEADERS = \
|
|||
gstplayprivate.h \
|
||||
full-screen.h
|
||||
|
||||
|
||||
libgstmediaplay_la_LDFLAGS = -rdynamic
|
||||
|
||||
gstmediaplay_CFLAGS = $(LIBGLADE_GNOME_CFLAGS)
|
||||
|
|
|
@ -39,12 +39,11 @@ target_drag_data_received (GtkWidget *widget,
|
|||
guint time,
|
||||
GstMediaPlay *play)
|
||||
{
|
||||
if (strstr (data->data, "file:")) {
|
||||
g_print ("Got: %s\n", &data->data[5]);
|
||||
g_print ("Got: %s\n", data->data);
|
||||
gdk_threads_leave ();
|
||||
gst_media_play_start_uri (play, g_strchomp (&data->data[5]));
|
||||
gst_media_play_start_uri (play, g_strchomp (data->data));
|
||||
gdk_threads_enter ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static GtkTargetEntry target_table[] = {
|
||||
|
|
|
@ -508,6 +508,7 @@ Arik Devens <arik@gnome.org>
|
|||
<last_modification_time>Sun, 06 Aug 2000 15:55:52 GMT</last_modification_time>
|
||||
</signal>
|
||||
<stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
|
||||
<relief>GTK_RELIEF_NORMAL</relief>
|
||||
</widget>
|
||||
|
||||
<widget>
|
||||
|
@ -523,6 +524,7 @@ Arik Devens <arik@gnome.org>
|
|||
<last_modification_time>Sun, 06 Aug 2000 15:53:48 GMT</last_modification_time>
|
||||
</signal>
|
||||
<stock_button>GNOME_STOCK_BUTTON_CANCEL</stock_button>
|
||||
<relief>GTK_RELIEF_NORMAL</relief>
|
||||
</widget>
|
||||
</widget>
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include <config.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "gstplay.h"
|
||||
#include "gstplayprivate.h"
|
||||
#include "full-screen.h"
|
||||
|
@ -118,10 +120,8 @@ gst_play_init (GstPlay *play)
|
|||
play->priv = priv;
|
||||
|
||||
/* create a new bin to hold the elements */
|
||||
priv->thread = gst_thread_new ("main_thread");
|
||||
g_assert (priv->thread != NULL);
|
||||
priv->bin = gst_bin_new ("main_bin");
|
||||
g_assert (priv->bin != NULL);
|
||||
priv->pipeline = gst_pipeline_new ("main_pipeline");
|
||||
g_assert (priv->pipeline != NULL);
|
||||
|
||||
priv->audio_element = gst_elementfactory_make ("osssink", "play_audio");
|
||||
g_return_if_fail (priv->audio_element != NULL);
|
||||
|
@ -165,6 +165,12 @@ gst_play_new ()
|
|||
return GST_PLAY (gtk_type_new (GST_TYPE_PLAY));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_play_idle_func (gpointer data)
|
||||
{
|
||||
return gst_bin_iterate (GST_BIN (data));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_play_eos (GstElement *element,
|
||||
GstPlay *play)
|
||||
|
@ -273,53 +279,68 @@ gst_play_object_added (GstAutoplug* autoplug, GstObject *object, GstPlay *play)
|
|||
}
|
||||
|
||||
static void
|
||||
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
|
||||
gst_play_cache_empty (GstElement *element, GstPlay *play)
|
||||
{
|
||||
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
|
||||
GstPlayPrivate *priv;
|
||||
GstElement *new_element;
|
||||
|
||||
*(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*
|
||||
gst_play_typefind (GstBin *bin, GstElement *element)
|
||||
static void
|
||||
gst_play_have_type (GstElement *sink, GstCaps *caps, GstPlay *play)
|
||||
{
|
||||
gboolean found = FALSE;
|
||||
GstElement *typefind;
|
||||
GstCaps *caps = NULL;
|
||||
GstPlayPrivate *priv;
|
||||
GstElement *new_element;
|
||||
GstAutoplug *autoplug;
|
||||
|
||||
GST_DEBUG (0, "GstPipeline: typefind for element \"%s\" %p\n",
|
||||
GST_ELEMENT_NAME (element), &found);
|
||||
GST_DEBUG (0,"GstPipeline: play have type\n");
|
||||
|
||||
typefind = gst_elementfactory_make ("typefind", "typefind");
|
||||
g_return_val_if_fail (typefind != NULL, FALSE);
|
||||
priv = (GstPlayPrivate *)play->priv;
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
|
||||
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
|
||||
gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
|
||||
|
||||
gst_pad_connect (gst_element_get_pad (element, "src"),
|
||||
gst_element_get_pad (typefind, "sink"));
|
||||
gst_element_disconnect (priv->cache, "src", priv->typefind, "sink");
|
||||
gst_bin_remove (GST_BIN (priv->pipeline), priv->typefind);
|
||||
|
||||
gst_bin_add (bin, typefind);
|
||||
autoplug = gst_autoplugfactory_make ("staticrender");
|
||||
g_assert (autoplug != NULL);
|
||||
|
||||
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
|
||||
gst_bin_iterate (bin);
|
||||
new_element = gst_autoplug_to_renderers (autoplug,
|
||||
caps,
|
||||
priv->video_element,
|
||||
priv->audio_element,
|
||||
NULL);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
|
||||
|
||||
if (found) {
|
||||
caps = gst_util_get_pointer_arg (GTK_OBJECT (typefind), "caps");
|
||||
|
||||
gst_pad_set_caps (gst_element_get_pad (element, "src"), caps);
|
||||
if (!new_element) {
|
||||
// FIXME, signal a suitable error
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
gst_element_set_name (new_element, "new_element");
|
||||
|
||||
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
|
||||
|
@ -349,9 +370,7 @@ GstPlayReturn
|
|||
gst_play_set_uri (GstPlay *play, const guchar *uri)
|
||||
{
|
||||
GstPlayPrivate *priv;
|
||||
GstCaps *src_caps;
|
||||
GstElement *new_element;
|
||||
GstAutoplug *autoplug;
|
||||
gchar* uriloc;
|
||||
|
||||
g_return_val_if_fail (play != NULL, GST_PLAY_ERROR);
|
||||
g_return_val_if_fail (GST_IS_PLAY (play), GST_PLAY_ERROR);
|
||||
|
@ -362,47 +381,51 @@ gst_play_set_uri (GstPlay *play, const guchar *uri)
|
|||
if (priv->uri)
|
||||
g_free (priv->uri);
|
||||
|
||||
priv->uri = g_strdup (uri);
|
||||
|
||||
priv->src = gst_elementfactory_make ("disksrc", "disk_src");
|
||||
//priv->src = gst_elementfactory_make ("dvdsrc", "disk_src");
|
||||
priv->offset_element = priv->src;
|
||||
/* see if it looks like a ARI */
|
||||
if ((uriloc = strstr (uri, ":/"))) {
|
||||
priv->src = gst_elementfactory_make ("gnomevfssrc", "srcelement");
|
||||
|
||||
g_return_val_if_fail (priv->src != NULL, -1);
|
||||
gtk_object_set (GTK_OBJECT (priv->src), "location", uri, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (priv->bin), priv->src);
|
||||
|
||||
src_caps = gst_play_typefind (GST_BIN (priv->bin), priv->src);
|
||||
|
||||
if (!src_caps) {
|
||||
return GST_PLAY_UNKNOWN_MEDIA;
|
||||
if (!priv->src) {
|
||||
if (strstr (uri, "file:/")) {
|
||||
uri += strlen ("file:/");
|
||||
}
|
||||
|
||||
autoplug = gst_autoplugfactory_make ("staticrender");
|
||||
g_assert (autoplug != NULL);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (autoplug), "new_object", gst_play_object_added, play);
|
||||
|
||||
new_element = gst_autoplug_to_renderers (autoplug,
|
||||
gst_pad_get_caps (gst_element_get_pad (priv->src, "src")),
|
||||
priv->video_element,
|
||||
priv->audio_element,
|
||||
NULL);
|
||||
|
||||
if (!new_element) {
|
||||
else
|
||||
return GST_PLAY_CANNOT_PLAY;
|
||||
}
|
||||
}
|
||||
|
||||
gst_bin_remove (GST_BIN (priv->bin), priv->src);
|
||||
gst_bin_add (GST_BIN (priv->thread), priv->src);
|
||||
if (priv->src == NULL) {
|
||||
priv->src = gst_elementfactory_make ("disksrc", "srcelement");
|
||||
}
|
||||
|
||||
gst_bin_add (GST_BIN (priv->bin), new_element);
|
||||
priv->uri = g_strdup (uri);
|
||||
|
||||
gst_element_connect (priv->src, "src", new_element, "sink");
|
||||
//priv->src = gst_elementfactory_make ("dvdsrc", "disk_src");
|
||||
priv->offset_element = priv->src;
|
||||
g_return_val_if_fail (priv->src != NULL, GST_PLAY_CANNOT_PLAY);
|
||||
|
||||
gst_bin_add (GST_BIN (priv->thread), priv->bin);
|
||||
gtk_signal_connect (GTK_OBJECT (priv->thread), "eos", GTK_SIGNAL_FUNC (gst_play_eos), play);
|
||||
gtk_object_set (GTK_OBJECT (priv->src), "location", priv->uri, NULL);
|
||||
|
||||
|
||||
priv->cache = gst_elementfactory_make ("autoplugcache", "cache");
|
||||
g_return_val_if_fail (priv->cache != NULL, GST_PLAY_CANNOT_PLAY);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (priv->cache), "cache_empty",
|
||||
GTK_SIGNAL_FUNC (gst_play_cache_empty), play);
|
||||
|
||||
priv->typefind = gst_elementfactory_make ("typefind", "typefind");
|
||||
g_return_val_if_fail (priv->typefind != NULL, GST_PLAY_CANNOT_PLAY);
|
||||
gtk_signal_connect (GTK_OBJECT (priv->typefind), "have_type",
|
||||
GTK_SIGNAL_FUNC (gst_play_have_type), play);
|
||||
|
||||
|
||||
gst_bin_add (GST_BIN (priv->pipeline), priv->src);
|
||||
gst_bin_add (GST_BIN (priv->pipeline), priv->cache);
|
||||
gst_bin_add (GST_BIN (priv->pipeline), priv->typefind);
|
||||
|
||||
gst_element_connect (priv->src, "src", priv->cache, "sink");
|
||||
gst_element_connect (priv->cache, "src", priv->typefind, "sink");
|
||||
|
||||
return GST_PLAY_OK;
|
||||
}
|
||||
|
@ -449,10 +472,11 @@ gst_play_play (GstPlay *play)
|
|||
if (play->state == GST_PLAY_PLAYING) return;
|
||||
|
||||
if (play->state == GST_PLAY_STOPPED)
|
||||
gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_READY);
|
||||
gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_PLAYING);
|
||||
gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_READY);
|
||||
gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_PLAYING);
|
||||
|
||||
play->state = GST_PLAY_PLAYING;
|
||||
gtk_idle_add (gst_play_idle_func, priv->pipeline);
|
||||
|
||||
gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
|
||||
play->state);
|
||||
|
@ -470,9 +494,10 @@ gst_play_pause (GstPlay *play)
|
|||
|
||||
if (play->state != GST_PLAY_PLAYING) return;
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_PAUSED);
|
||||
gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_PAUSED);
|
||||
|
||||
play->state = GST_PLAY_PAUSED;
|
||||
g_idle_remove_by_data (priv->pipeline);
|
||||
|
||||
gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
|
||||
play->state);
|
||||
|
@ -491,11 +516,12 @@ gst_play_stop (GstPlay *play)
|
|||
priv = (GstPlayPrivate *)play->priv;
|
||||
|
||||
// FIXME until state changes are handled properly
|
||||
gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_READY);
|
||||
gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_READY);
|
||||
gtk_object_set (GTK_OBJECT (priv->src),"offset",0,NULL);
|
||||
//gst_element_set_state (GST_ELEMENT (priv->thread),GST_STATE_NULL);
|
||||
//gst_element_set_state (GST_ELEMENT (priv->pipeline),GST_STATE_NULL);
|
||||
|
||||
play->state = GST_PLAY_STOPPED;
|
||||
g_idle_remove_by_data (priv->pipeline);
|
||||
|
||||
gtk_signal_emit (GTK_OBJECT (play), gst_play_signals[SIGNAL_STATE_CHANGED],
|
||||
play->state);
|
||||
|
@ -653,7 +679,7 @@ gst_play_get_pipeline (GstPlay *play)
|
|||
|
||||
priv = (GstPlayPrivate *)play->priv;
|
||||
|
||||
return GST_ELEMENT (priv->bin);
|
||||
return GST_ELEMENT (priv->pipeline);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -6,12 +6,13 @@
|
|||
typedef struct _GstPlayPrivate GstPlayPrivate;
|
||||
|
||||
struct _GstPlayPrivate {
|
||||
GstElement *thread;
|
||||
GstElement *bin;
|
||||
GstElement *pipeline;
|
||||
GstElement *video_element, *audio_element;
|
||||
GstElement *video_show;
|
||||
GtkWidget *video_widget;
|
||||
GstElement *src;
|
||||
GstElement *cache;
|
||||
GstElement *typefind;
|
||||
|
||||
guchar *uri;
|
||||
gboolean muted;
|
||||
|
|
11
gstreamer-uninstalled.pc.in
Normal file
11
gstreamer-uninstalled.pc.in
Normal 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
11
gstreamer.pc.in
Normal 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:
|
|
@ -84,3 +84,4 @@ make prefix=$RPM_BUILD_ROOT%{prefix} install
|
|||
%{prefix}/include/*
|
||||
%{prefix}/lib/lib*.a
|
||||
%{prefix}/lib/lib*.so
|
||||
%{prefix}/lib/pkgconfig/*
|
||||
|
|
|
@ -53,38 +53,38 @@ GstIDCT *gst_idct_new(GstIDCTMethod method)
|
|||
|
||||
switch (method) {
|
||||
case GST_IDCT_FAST_INT:
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using fast_int_idct\n");
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "using fast_int_idct");
|
||||
gst_idct_init_fast_int_idct();
|
||||
new->convert = gst_idct_fast_int_idct;
|
||||
break;
|
||||
case GST_IDCT_INT:
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using int_idct\n");
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "using int_idct");
|
||||
new->convert = gst_idct_int_idct;
|
||||
break;
|
||||
case GST_IDCT_FLOAT:
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using float_idct\n");
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "using float_idct");
|
||||
gst_idct_init_float_idct();
|
||||
new->convert = gst_idct_float_idct;
|
||||
break;
|
||||
#ifdef HAVE_LIBMMX
|
||||
case GST_IDCT_MMX:
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using MMX_idct\n");
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "using MMX_idct");
|
||||
new->convert = gst_idct_mmx_idct;
|
||||
new->need_transpose = TRUE;
|
||||
break;
|
||||
case GST_IDCT_MMX32:
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using MMX32_idct\n");
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "using MMX32_idct");
|
||||
new->convert = gst_idct_mmx32_idct;
|
||||
new->need_transpose = TRUE;
|
||||
break;
|
||||
case GST_IDCT_SSE:
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: using SSE_idct\n");
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "using SSE_idct");
|
||||
new->convert = gst_idct_sse_idct;
|
||||
new->need_transpose = TRUE;
|
||||
break;
|
||||
#endif /* HAVE_LIBMMX */
|
||||
default:
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "GstIDCT: method not supported\n");
|
||||
GST_INFO (GST_CAT_PLUGIN_INFO, "method not supported");
|
||||
g_free(new);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ enum {
|
|||
ARG_OUTPUT,
|
||||
ARG_PATTERN,
|
||||
ARG_NUM_BUFFERS,
|
||||
ARG_EOS,
|
||||
ARG_SILENT
|
||||
};
|
||||
|
||||
|
@ -125,6 +126,8 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
|
|||
GTK_ARG_READWRITE, ARG_PATTERN);
|
||||
gtk_object_add_arg_type ("GstFakeSrc::num_buffers", GTK_TYPE_INT,
|
||||
GTK_ARG_READWRITE, ARG_NUM_BUFFERS);
|
||||
gtk_object_add_arg_type ("GstFakeSrc::eos", GTK_TYPE_BOOL,
|
||||
GTK_ARG_READWRITE, ARG_EOS);
|
||||
gtk_object_add_arg_type ("GstFakeSrc::silent", GTK_TYPE_BOOL,
|
||||
GTK_ARG_READWRITE, ARG_SILENT);
|
||||
|
||||
|
@ -222,6 +225,10 @@ gst_fakesrc_set_arg (GtkObject *object, GtkArg *arg, guint id)
|
|||
case ARG_NUM_BUFFERS:
|
||||
src->num_buffers = GTK_VALUE_INT (*arg);
|
||||
break;
|
||||
case ARG_EOS:
|
||||
src->eos = GTK_VALUE_BOOL (*arg);
|
||||
GST_INFO (0, "will EOS on next buffer");
|
||||
break;
|
||||
case ARG_SILENT:
|
||||
src->silent = GTK_VALUE_BOOL (*arg);
|
||||
break;
|
||||
|
@ -256,6 +263,8 @@ gst_fakesrc_get_arg (GtkObject *object, GtkArg *arg, guint id)
|
|||
case ARG_NUM_BUFFERS:
|
||||
GTK_VALUE_INT (*arg) = src->num_buffers;
|
||||
break;
|
||||
case ARG_EOS:
|
||||
GTK_VALUE_BOOL (*arg) = src->eos;
|
||||
case ARG_SILENT:
|
||||
GTK_VALUE_BOOL (*arg) = src->silent;
|
||||
break;
|
||||
|
@ -295,6 +304,12 @@ gst_fakesrc_get(GstPad *pad)
|
|||
src->num_buffers--;
|
||||
}
|
||||
|
||||
if (src->eos) {
|
||||
GST_INFO (0, "fakesrc is setting eos on pad");
|
||||
gst_pad_set_eos (pad);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!src->silent)
|
||||
g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad));
|
||||
buf = gst_buffer_new();
|
||||
|
@ -339,6 +354,12 @@ gst_fakesrc_loop(GstElement *element)
|
|||
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();
|
||||
if (!src->silent)
|
||||
g_print("fakesrc: ******* (%s:%s)> \n",GST_DEBUG_PAD_NAME(pad));
|
||||
|
|
|
@ -65,6 +65,7 @@ struct _GstFakeSrc {
|
|||
GstElement element;
|
||||
|
||||
gboolean loop_based;
|
||||
gboolean eos;
|
||||
gint numsrcpads;
|
||||
GSList *srcpads;
|
||||
GstFakeSrcOutputType output;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
//#define DEBUG_ENABLED
|
||||
//#define STATUS_ENABLED
|
||||
#ifdef STATUS_ENABLED
|
||||
#define STATUS(A) GST_DEBUG(0,A, gst_element_get_name(GST_ELEMENT(queue)))
|
||||
#define STATUS(A) GST_DEBUG(GST_CAT_DATAFLOW, A, GST_ELEMENT_NAME(queue))
|
||||
#else
|
||||
#define STATUS(A)
|
||||
#endif
|
||||
|
@ -34,6 +34,7 @@
|
|||
#include "gst_private.h"
|
||||
|
||||
#include "gstqueue.h"
|
||||
#include "gstscheduler.h"
|
||||
|
||||
GstElementDetails gst_queue_details = {
|
||||
"Queue",
|
||||
|
@ -47,15 +48,22 @@ GstElementDetails gst_queue_details = {
|
|||
|
||||
/* Queue signals and args */
|
||||
enum {
|
||||
/* FILL ME */
|
||||
LOW_WATERMARK,
|
||||
HIGH_WATERMARK,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_LEVEL_BUFFERS,
|
||||
ARG_LEVEL_BYTES,
|
||||
ARG_LEVEL_TIME,
|
||||
ARG_SIZE_BUFFERS,
|
||||
ARG_SIZE_BYTES,
|
||||
ARG_SIZE_TIME,
|
||||
ARG_LEAKY,
|
||||
ARG_LEVEL,
|
||||
ARG_MAX_LEVEL,
|
||||
ARG_BLOCK,
|
||||
};
|
||||
|
||||
|
||||
|
@ -77,6 +85,23 @@ static void gst_queue_flush (GstQueue *queue);
|
|||
static GstElementStateReturn gst_queue_change_state (GstElement *element);
|
||||
|
||||
|
||||
static GtkType
|
||||
queue_leaky_get_type(void) {
|
||||
static GtkType queue_leaky_type = 0;
|
||||
static GtkEnumValue queue_leaky[] = {
|
||||
{ GST_QUEUE_NO_LEAK, "0", "Not Leaky" },
|
||||
{ GST_QUEUE_LEAK_UPSTREAM, "1", "Leaky on Upstream" },
|
||||
{ GST_QUEUE_LEAK_DOWNSTREAM, "2", "Leaky on Downstream" },
|
||||
{ 0, NULL, NULL },
|
||||
};
|
||||
if (!queue_leaky_type) {
|
||||
queue_leaky_type = gtk_type_register_enum("GstQueueLeaky", queue_leaky);
|
||||
}
|
||||
return queue_leaky_type;
|
||||
}
|
||||
#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type())
|
||||
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
//static guint gst_queue_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
@ -111,12 +136,12 @@ gst_queue_class_init (GstQueueClass *klass)
|
|||
|
||||
parent_class = gtk_type_class (GST_TYPE_ELEMENT);
|
||||
|
||||
gtk_object_add_arg_type ("GstQueue::leaky", GST_TYPE_QUEUE_LEAKY,
|
||||
GTK_ARG_READWRITE, ARG_LEAKY);
|
||||
gtk_object_add_arg_type ("GstQueue::level", GTK_TYPE_INT,
|
||||
GTK_ARG_READABLE, ARG_LEVEL);
|
||||
gtk_object_add_arg_type ("GstQueue::max_level", GTK_TYPE_INT,
|
||||
GTK_ARG_READWRITE, ARG_MAX_LEVEL);
|
||||
gtk_object_add_arg_type ("GstQueue::block", GTK_TYPE_BOOL,
|
||||
GTK_ARG_READWRITE, ARG_BLOCK);
|
||||
|
||||
gtkobject_class->set_arg = gst_queue_set_arg;
|
||||
gtkobject_class->get_arg = gst_queue_get_arg;
|
||||
|
@ -144,14 +169,15 @@ gst_queue_init (GstQueue *queue)
|
|||
|
||||
queue->queue = NULL;
|
||||
queue->level_buffers = 0;
|
||||
queue->max_buffers = 100;
|
||||
queue->block = TRUE;
|
||||
queue->level_bytes = 0;
|
||||
queue->size_buffers = 0;
|
||||
queue->size_bytes = 0;
|
||||
queue->level_time = 0LL;
|
||||
queue->size_buffers = 100; // 100 buffers
|
||||
queue->size_bytes = 100 * 1024; // 100KB
|
||||
queue->size_time = 1000000000LL; // 1sec
|
||||
|
||||
queue->emptycond = g_cond_new ();
|
||||
queue->fullcond = g_cond_new ();
|
||||
GST_DEBUG(GST_CAT_THREAD, "initialized queue's emptycond and fullcond\n");
|
||||
}
|
||||
|
||||
static GstBufferPool*
|
||||
|
@ -206,10 +232,10 @@ gst_queue_handle_eos (GstPad *pad)
|
|||
|
||||
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
|
||||
|
||||
GST_DEBUG (0,"queue: %s received eos\n", GST_ELEMENT_NAME (queue));
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s received eos\n", GST_ELEMENT_NAME (queue));
|
||||
|
||||
GST_LOCK (queue);
|
||||
GST_DEBUG (0,"queue: %s has %d buffers left\n", GST_ELEMENT_NAME (queue),
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s has %d buffers left\n", GST_ELEMENT_NAME (queue),
|
||||
queue->level_buffers);
|
||||
|
||||
GST_FLAG_SET (pad, GST_PAD_EOS);
|
||||
|
@ -224,7 +250,7 @@ gst_queue_handle_eos (GstPad *pad)
|
|||
static void
|
||||
gst_queue_cleanup_buffers (gpointer data, const gpointer user_data)
|
||||
{
|
||||
GST_DEBUG (0,"queue: %s cleaning buffer %p\n", (gchar *)user_data, data);
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s cleaning buffer %p\n", (gchar *)user_data, data);
|
||||
|
||||
gst_buffer_unref (GST_BUFFER (data));
|
||||
}
|
||||
|
@ -257,45 +283,79 @@ gst_queue_chain (GstPad *pad, GstBuffer *buf)
|
|||
|
||||
/* we have to lock the queue since we span threads */
|
||||
|
||||
GST_DEBUG (0,"queue: try have queue lock\n");
|
||||
// GST_DEBUG (GST_CAT_DATAFLOW,"trying to get lock on queue \"%s\"\n",name);
|
||||
GST_LOCK (queue);
|
||||
GST_DEBUG (0,"queue: %s adding buffer %p %ld\n", name, buf, pthread_self ());
|
||||
GST_DEBUG (0,"queue: have queue lock\n");
|
||||
|
||||
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH)) {
|
||||
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "buffer has FLUSH bit set, flushing queue\n");
|
||||
gst_queue_flush (queue);
|
||||
}
|
||||
|
||||
GST_DEBUG (0,"queue: %s: chain %d %p\n", name, queue->level_buffers, buf);
|
||||
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "adding buffer %p of size %d\n",buf,GST_BUFFER_SIZE(buf));
|
||||
|
||||
while (queue->level_buffers >= queue->max_buffers) {
|
||||
GST_DEBUG (0,"queue: %s waiting %d\n", name, queue->level_buffers);
|
||||
STATUS("%s: O\n");
|
||||
//g_cond_timed_wait (queue->fullcond, queue->fulllock, queue->timeval);
|
||||
//FIXME need to signal other thread in case signals got lost?
|
||||
if (queue->level_buffers >= queue->size_buffers) {
|
||||
// if this is a leaky queue...
|
||||
if (queue->leaky) {
|
||||
// if we leak on the upstream side, drop the current buffer
|
||||
if (queue->leaky == GST_QUEUE_LEAK_UPSTREAM) {
|
||||
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on upstream end\n");
|
||||
gst_buffer_unref(buf);
|
||||
// now we have to clean up and exit right away
|
||||
GST_UNLOCK (queue);
|
||||
return;
|
||||
}
|
||||
// otherwise we have to push a buffer off the other end
|
||||
else {
|
||||
GSList *front;
|
||||
GstBuffer *leakbuf;
|
||||
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end\n");
|
||||
front = queue->queue;
|
||||
leakbuf = (GstBuffer *)(front->data);
|
||||
queue->level_buffers--;
|
||||
queue->level_bytes -= GST_BUFFER_SIZE(leakbuf);
|
||||
gst_buffer_unref(leakbuf);
|
||||
queue->queue = g_slist_remove_link (queue->queue, front);
|
||||
g_slist_free (front);
|
||||
}
|
||||
}
|
||||
|
||||
while (queue->level_buffers >= queue->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);
|
||||
STATUS("%s: O+\n");
|
||||
GST_DEBUG (0,"queue: %s waiting done %d\n", name, queue->level_buffers);
|
||||
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "done waiting, level is now %d\n", queue->level_buffers);
|
||||
}
|
||||
}
|
||||
|
||||
/* put the buffer on the tail of the list */
|
||||
queue->queue = g_slist_append (queue->queue, buf);
|
||||
// STATUS("%s: +\n");
|
||||
GST_DEBUG (0,"(%s:%s)+ ",GST_DEBUG_PAD_NAME(pad));
|
||||
queue->level_buffers++;
|
||||
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 */
|
||||
tosignal = (queue->level_buffers >= 0);
|
||||
queue->level_buffers++;
|
||||
|
||||
/* we can unlock now */
|
||||
GST_DEBUG (0,"queue: %s chain %d end signal(%d,%p)\n", name, queue->level_buffers, tosignal, queue->emptycond);
|
||||
|
||||
if (tosignal) {
|
||||
// STATUS("%s: >\n");
|
||||
if (queue->level_buffers == 1)
|
||||
{
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling emptycond\n", name);
|
||||
g_cond_signal (queue->emptycond);
|
||||
// STATUS("%s: >>\n");
|
||||
}
|
||||
|
||||
GST_UNLOCK (queue);
|
||||
}
|
||||
|
||||
|
@ -307,6 +367,8 @@ gst_queue_get (GstPad *pad)
|
|||
GSList *front;
|
||||
const guchar *name;
|
||||
|
||||
g_assert(pad != NULL);
|
||||
g_assert(GST_IS_PAD(pad));
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||
|
||||
|
@ -314,63 +376,74 @@ gst_queue_get (GstPad *pad)
|
|||
name = GST_ELEMENT_NAME (queue);
|
||||
|
||||
/* have to lock for thread-safety */
|
||||
GST_DEBUG (0,"queue: %s try have queue lock\n", name);
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s try have queue lock\n", name);
|
||||
GST_LOCK (queue);
|
||||
GST_DEBUG (0,"queue: %s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
|
||||
GST_DEBUG (0,"queue: %s have queue lock\n", name);
|
||||
|
||||
// we bail if there's nothing there
|
||||
if (!queue->level_buffers && !queue->block) {
|
||||
GST_UNLOCK(queue);
|
||||
return NULL;
|
||||
}
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s push %d %ld %p\n", name, queue->level_buffers, pthread_self (), queue->emptycond);
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s have queue lock\n", name);
|
||||
|
||||
while (!queue->level_buffers) {
|
||||
STATUS("queue: %s U released lock\n");
|
||||
//g_cond_timed_wait (queue->emptycond, queue->emptylock, queue->timeval);
|
||||
if (GST_FLAG_IS_SET (queue->sinkpad, GST_PAD_EOS)) {
|
||||
GST_DEBUG (GST_CAT_DATAFLOW, "%s U released lock\n", name);
|
||||
GST_UNLOCK(queue);
|
||||
gst_pad_set_eos (queue->srcpad);
|
||||
// this return NULL shouldn't hurt anything...
|
||||
return NULL;
|
||||
}
|
||||
//FIXME need to signal other thread in case signals got lost?
|
||||
|
||||
// if there's a pending state change for this queue or its manager, switch
|
||||
// back to iterator so bottom half of state change executes
|
||||
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING ||
|
||||
// GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
|
||||
GST_STATE_PENDING(GST_SCHED_PARENT(GST_ELEMENT_SCHED(GST_PAD_PARENT(GST_PAD_PEER(queue->srcpad))))) !=
|
||||
GST_STATE_NONE_PENDING)
|
||||
{
|
||||
GST_DEBUG(GST_CAT_DATAFLOW,"interrupted!!\n");
|
||||
if (GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)
|
||||
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(queue) != GST_STATE_NONE_PENDING)\n");
|
||||
if (GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING)
|
||||
GST_DEBUG(GST_CAT_DATAFLOW,"GST_STATE_PENDING(GST_SCHEDULE(GST_ELEMENT(queue)->sched)->parent) != GST_STATE_NONE_PENDING\n");
|
||||
GST_UNLOCK(queue);
|
||||
cothread_switch(cothread_current_main());
|
||||
}
|
||||
|
||||
g_cond_signal (queue->fullcond);
|
||||
g_cond_wait (queue->emptycond, GST_OBJECT(queue)->lock);
|
||||
// STATUS("queue: %s U- getting lock\n");
|
||||
}
|
||||
|
||||
front = queue->queue;
|
||||
buf = (GstBuffer *)(front->data);
|
||||
GST_DEBUG (0,"retrieved buffer %p from queue\n",buf);
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"retrieved buffer %p from queue\n",buf);
|
||||
queue->queue = g_slist_remove_link (queue->queue, front);
|
||||
g_slist_free (front);
|
||||
|
||||
queue->level_buffers--;
|
||||
// STATUS("%s: -\n");
|
||||
GST_DEBUG (0,"(%s:%s)- ",GST_DEBUG_PAD_NAME(pad));
|
||||
|
||||
if (queue->level_buffers < queue->max_buffers) {
|
||||
// STATUS("%s: < \n");
|
||||
// if (queue->level_buffers < queue->size_buffers)
|
||||
if (queue->level_buffers == queue->size_buffers)
|
||||
{
|
||||
GST_DEBUG (GST_CAT_DATAFLOW,"%s signalling fullcond\n", name);
|
||||
g_cond_signal (queue->fullcond);
|
||||
// STATUS("%s: << \n");
|
||||
}
|
||||
|
||||
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_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;
|
||||
/* unlock now */
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_queue_change_state (GstElement *element)
|
||||
{
|
||||
GstQueue *queue;
|
||||
GstElementStateReturn ret;
|
||||
g_return_val_if_fail (GST_IS_QUEUE (element), GST_STATE_FAILURE);
|
||||
|
||||
queue = GST_QUEUE (element);
|
||||
GST_DEBUG (0,"gstqueue: state pending %d\n", GST_STATE_PENDING (element));
|
||||
|
||||
// lock the queue so another thread (not in sync with this thread's state)
|
||||
// can't call this queue's _get (or whatever)
|
||||
GST_LOCK (queue);
|
||||
|
||||
/* if going down into NULL state, clear out buffers*/
|
||||
if (GST_STATE_PENDING (element) == GST_STATE_READY) {
|
||||
|
@ -380,9 +453,41 @@ gst_queue_change_state (GstElement *element)
|
|||
|
||||
/* if we haven't failed already, give the parent class a chance to ;-) */
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
{
|
||||
gboolean valid_handler = FALSE;
|
||||
guint state_change_id = gtk_signal_lookup("state_change", GTK_OBJECT_TYPE(element));
|
||||
|
||||
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);
|
||||
|
||||
switch(id) {
|
||||
case ARG_MAX_LEVEL:
|
||||
queue->max_buffers = GTK_VALUE_INT (*arg);
|
||||
case ARG_LEAKY:
|
||||
queue->leaky = GTK_VALUE_INT (*arg);
|
||||
break;
|
||||
case ARG_BLOCK:
|
||||
queue->block = GTK_VALUE_BOOL (*arg);
|
||||
case ARG_MAX_LEVEL:
|
||||
queue->size_buffers = GTK_VALUE_INT (*arg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -419,14 +524,14 @@ gst_queue_get_arg (GtkObject *object, GtkArg *arg, guint id)
|
|||
queue = GST_QUEUE (object);
|
||||
|
||||
switch (id) {
|
||||
case ARG_LEAKY:
|
||||
GTK_VALUE_INT (*arg) = queue->leaky;
|
||||
break;
|
||||
case ARG_LEVEL:
|
||||
GTK_VALUE_INT (*arg) = queue->level_buffers;
|
||||
break;
|
||||
case ARG_MAX_LEVEL:
|
||||
GTK_VALUE_INT (*arg) = queue->max_buffers;
|
||||
break;
|
||||
case ARG_BLOCK:
|
||||
GTK_VALUE_BOOL (*arg) = queue->block;
|
||||
GTK_VALUE_INT (*arg) = queue->size_buffers;
|
||||
break;
|
||||
default:
|
||||
arg->type = GTK_TYPE_INVALID;
|
||||
|
|
|
@ -47,6 +47,12 @@ GstElementDetails gst_queue_details;
|
|||
#define GST_IS_QUEUE_CLASS(obj) \
|
||||
(GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_QUEUE))
|
||||
|
||||
enum {
|
||||
GST_QUEUE_NO_LEAK = 0,
|
||||
GST_QUEUE_LEAK_UPSTREAM = 1,
|
||||
GST_QUEUE_LEAK_DOWNSTREAM = 2
|
||||
};
|
||||
|
||||
typedef struct _GstQueue GstQueue;
|
||||
typedef struct _GstQueueClass GstQueueClass;
|
||||
|
||||
|
@ -60,12 +66,16 @@ struct _GstQueue {
|
|||
GSList *queue;
|
||||
|
||||
gint level_buffers; /* number of buffers queued here */
|
||||
gint max_buffers; /* maximum number of buffers queued here */
|
||||
gboolean block; /* if set to FALSE, _get returns NULL if queue empty */
|
||||
gint level_bytes; /* number of bytes queued here */
|
||||
guint64 level_time; /* amount of time queued here */
|
||||
|
||||
gint size_buffers; /* size of queue in buffers */
|
||||
gint size_bytes; /* size of queue in bytes */
|
||||
guint64 size_time; /* size of queue in time */
|
||||
|
||||
gint leaky; /* whether the queue is leaky, and if so at which end */
|
||||
|
||||
// GMutex *lock; (optimization?)
|
||||
GCond *emptycond;
|
||||
GCond *fullcond;
|
||||
|
||||
|
@ -74,6 +84,10 @@ struct _GstQueue {
|
|||
|
||||
struct _GstQueueClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
/* signal callbacks */
|
||||
void (*low_watermark) (GstQueue *queue, gint level);
|
||||
void (*high_watermark) (GstQueue *queue, gint level);
|
||||
};
|
||||
|
||||
GtkType gst_queue_get_type (void);
|
||||
|
|
1
test/.gitignore
vendored
1
test/.gitignore
vendored
|
@ -29,6 +29,7 @@ mp3parse
|
|||
mpeg2parse
|
||||
mpeg2parse2
|
||||
mpeg2parse3
|
||||
mpeg2parse4
|
||||
mp3play
|
||||
ac3parse
|
||||
ac3play
|
||||
|
|
|
@ -22,18 +22,6 @@ ac3play_SOURCES = ac3play.c mem.c
|
|||
|
||||
noinst_HEADERS = mem.h
|
||||
|
||||
if HAVE_LIBXV
|
||||
xvlibs=-lXv
|
||||
else
|
||||
xvlibs=
|
||||
endif
|
||||
|
||||
LDADD = ${xvlibs} -lXxf86vm $(GNOME_LIBS) $(GST_LIBS)
|
||||
|
||||
#LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la \
|
||||
# $(top_builddir)/plugins/videosink/libvideosink.la -L/usr/X11/lib -lXxf86dga
|
||||
#LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_builddir)/gst/libgst.la
|
||||
|
||||
LIBS += $(GNOME_LIBS) $(GST_LIBS)
|
||||
CFLAGS += $(GNOME_CFLAGS) $(GST_CFLAGS)
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ int main(int argc,char *argv[]) {
|
|||
g_return_val_if_fail(src != NULL, -1);
|
||||
gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
|
||||
g_print("should be using file '%s'\n",argv[1]);
|
||||
parse = gst_elementfactory_make("parseavi","parse");
|
||||
parse = gst_elementfactory_make("avidecoder","parse");
|
||||
g_return_val_if_fail(parse != NULL, -1);
|
||||
|
||||
mux = gst_elementfactory_make("system_encode","mux");
|
||||
|
|
|
@ -32,8 +32,6 @@ int main(int argc,char *argv[]) {
|
|||
gst_pad_connect(gst_element_get_pad(identity,"src"),
|
||||
gst_element_get_pad(sink,"sink"));
|
||||
|
||||
g_print("--- creating a plan\n");
|
||||
gst_bin_create_plan(GST_BIN(bin));
|
||||
|
||||
g_print("--- starting up\n");
|
||||
gst_bin_iterate(GST_BIN(bin));
|
||||
|
|
|
@ -29,7 +29,7 @@ main (int argc,char *argv[])
|
|||
|
||||
gnome_init("Videotest","0.0.1",argc,argv);
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
bin = gst_pipeline_new("pipeline");
|
||||
|
||||
if (argc == 1) {
|
||||
src = gst_elementfactory_make ("dv1394src", "src");
|
||||
|
|
|
@ -10,7 +10,7 @@ int main(int argc,char *argv[]) {
|
|||
// _gst_plugin_spew = TRUE;
|
||||
gst_init(&argc,&argv);
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
bin = gst_pipeline_new("pipeline");
|
||||
g_return_if_fail(bin != NULL);
|
||||
|
||||
g_print("--- creating src and sink elements\n");
|
||||
|
@ -35,8 +35,6 @@ int main(int argc,char *argv[]) {
|
|||
g_print("--- setting up\n");
|
||||
gst_element_set_state(GST_ELEMENT(bin),GST_STATE_READY);
|
||||
|
||||
g_print("--- creating plan\n");
|
||||
gst_bin_create_plan(bin);
|
||||
g_print("--- iterating\n");
|
||||
gst_bin_iterate(bin);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ int main(int argc,char *argv[]) {
|
|||
|
||||
gtk_socket = gtk_socket_new ();
|
||||
gtk_widget_show (gtk_socket);
|
||||
gtk_widget_set_usize(gtk_socket,320,240);
|
||||
|
||||
gnome_app_set_contents(GNOME_APP(appwindow),
|
||||
GTK_WIDGET(gtk_socket));
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include <gnome.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
GstElement *parse2, *v_queue, *a_queue;
|
||||
GstPipeline *pipeline;
|
||||
GstElement *v_queue, *a_queue, *v_thread, *a_thread;
|
||||
GtkWidget *appwindow;
|
||||
GtkWidget *gtk_socket;
|
||||
|
||||
void eof(GstElement *src) {
|
||||
g_print("have eos, quitting\n");
|
||||
|
@ -17,38 +19,37 @@ gboolean idle_func(gpointer data) {
|
|||
void mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) {
|
||||
|
||||
g_print("***** a new pad %s was created\n", gst_pad_get_name(pad));
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PAUSED);
|
||||
|
||||
if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) {
|
||||
gst_pad_connect(pad, gst_element_get_pad(v_queue,"sink"));
|
||||
gst_bin_add(GST_BIN(pipeline),v_thread);
|
||||
gst_element_set_state(v_thread,GST_STATE_PLAYING);
|
||||
} else if (strcmp(gst_pad_get_name(pad), "private_stream_1.0") == 0) {
|
||||
gst_pad_connect(pad, gst_element_get_pad(a_queue,"sink"));
|
||||
gst_bin_add(GST_BIN(pipeline),a_thread);
|
||||
gst_element_set_state(a_thread,GST_STATE_PLAYING);
|
||||
}
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
|
||||
}
|
||||
|
||||
void mpeg2parse_have_size(GstElement *videosink,gint width,gint height) {
|
||||
gtk_widget_set_usize(gtk_socket,width,height);
|
||||
gtk_widget_show_all(appwindow);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
GstPipeline *pipeline;
|
||||
GstElement *src, *parse;
|
||||
GstElement *v_thread, *v_decode, *show, *color;
|
||||
GstElement *a_thread, *a_decode, *osssink;
|
||||
GtkWidget *gtk_socket;
|
||||
GstElement *v_decode, *show, *color;
|
||||
GstElement *a_decode, *osssink;
|
||||
|
||||
g_print("have %d args\n",argc);
|
||||
|
||||
gst_init(&argc,&argv);
|
||||
gnome_init("MPEG2 Video player","0.0.1",argc,argv);
|
||||
//gst_plugin_load("mpeg1parse");
|
||||
|
||||
// ***** construct the main pipeline *****
|
||||
pipeline = GST_PIPELINE(gst_pipeline_new("pipeline"));
|
||||
g_return_val_if_fail(pipeline != NULL, -1);
|
||||
|
||||
v_thread = GST_ELEMENT(gst_thread_new("v_thread"));
|
||||
g_return_val_if_fail(v_thread != NULL, -1);
|
||||
|
||||
a_thread = GST_ELEMENT(gst_thread_new("a_thread"));
|
||||
g_return_val_if_fail(a_thread != NULL, -1);
|
||||
|
||||
if (strstr(argv[1],"video_ts")) {
|
||||
src = gst_elementfactory_make("dvdsrc","src");
|
||||
g_print("using DVD source\n");
|
||||
|
@ -68,20 +69,19 @@ int main(int argc,char *argv[]) {
|
|||
//parse = gst_elementfactory_make("mpeg1parse","parse");
|
||||
g_return_val_if_fail(parse != NULL, -1);
|
||||
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
|
||||
|
||||
gst_element_connect(src,"src",parse,"sink");
|
||||
|
||||
|
||||
// ***** pre-construct the video thread *****
|
||||
v_thread = GST_ELEMENT(gst_thread_new("v_thread"));
|
||||
g_return_val_if_fail(v_thread != NULL, -1);
|
||||
|
||||
v_queue = gst_elementfactory_make("queue","v_queue");
|
||||
g_return_val_if_fail(v_queue != NULL, -1);
|
||||
|
||||
a_queue = gst_elementfactory_make("queue","a_queue");
|
||||
g_return_val_if_fail(a_queue != NULL, -1);
|
||||
|
||||
/****
|
||||
* you can substitute mpeg2play with you own player here
|
||||
* optionally you can remove the parse2 element. make
|
||||
* sure to remove the pad connections too and don't add the
|
||||
* mp2videoparse element to the bin.
|
||||
**/
|
||||
//parse2 = gst_elementfactory_make("mp2videoparse","parse");
|
||||
//g_return_val_if_fail(parse2 != NULL, -1);
|
||||
v_decode = gst_elementfactory_make("mpeg2dec","decode_video");
|
||||
g_return_val_if_fail(v_decode != NULL, -1);
|
||||
|
||||
|
@ -89,16 +89,40 @@ int main(int argc,char *argv[]) {
|
|||
g_return_val_if_fail(color != NULL, -1);
|
||||
|
||||
show = gst_elementfactory_make("xvideosink","show");
|
||||
//show = gst_elementfactory_make("aasink","show");
|
||||
//gtk_object_set(GTK_OBJECT(show),"xv_enabled",FALSE,NULL);
|
||||
g_return_val_if_fail(show != NULL, -1);
|
||||
|
||||
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_queue));
|
||||
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_decode));
|
||||
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(color));
|
||||
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(show));
|
||||
|
||||
gst_element_connect(v_queue,"src",v_decode,"sink");
|
||||
gst_element_connect(v_decode,"src",color,"sink");
|
||||
gst_element_connect(color,"src",show,"sink");
|
||||
|
||||
|
||||
// ***** pre-construct the audio thread *****
|
||||
a_thread = GST_ELEMENT(gst_thread_new("a_thread"));
|
||||
g_return_val_if_fail(a_thread != NULL, -1);
|
||||
|
||||
a_queue = gst_elementfactory_make("queue","a_queue");
|
||||
g_return_val_if_fail(a_queue != NULL, -1);
|
||||
|
||||
a_decode = gst_elementfactory_make("ac3dec","decode_audio");
|
||||
g_return_val_if_fail(a_decode != NULL, -1);
|
||||
|
||||
osssink = gst_elementfactory_make("osssink","osssink");
|
||||
g_return_val_if_fail(osssink != NULL, -1);
|
||||
|
||||
gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_queue));
|
||||
gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_decode));
|
||||
gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(osssink));
|
||||
|
||||
gst_element_connect(a_queue,"src",a_decode,"sink");
|
||||
gst_element_connect(a_decode,"src",osssink,"sink");
|
||||
|
||||
|
||||
// ***** construct the GUI *****
|
||||
appwindow = gnome_app_new("MPEG player","MPEG player");
|
||||
|
||||
gtk_socket = gtk_socket_new ();
|
||||
|
@ -111,45 +135,9 @@ int main(int argc,char *argv[]) {
|
|||
gtk_socket_steal (GTK_SOCKET (gtk_socket),
|
||||
gst_util_get_int_arg (GTK_OBJECT(show), "xid"));
|
||||
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(parse));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(v_queue));
|
||||
|
||||
//gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(parse2));
|
||||
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(v_decode));
|
||||
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(color));
|
||||
gst_bin_add(GST_BIN(v_thread),GST_ELEMENT(show));
|
||||
|
||||
gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(a_decode));
|
||||
gst_bin_add(GST_BIN(a_thread),GST_ELEMENT(osssink));
|
||||
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(v_thread));
|
||||
gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(a_thread));
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(parse),"new_pad",mpeg2parse_newpad, pipeline);
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(src),"eos",GTK_SIGNAL_FUNC(eof),NULL);
|
||||
|
||||
gst_pad_connect(gst_element_get_pad(src,"src"),
|
||||
gst_element_get_pad(parse,"sink"));
|
||||
|
||||
// video
|
||||
gst_pad_connect(gst_element_get_pad(v_queue,"src"),
|
||||
// gst_element_get_pad(parse2,"sink"));
|
||||
//gst_pad_connect(gst_element_get_pad(parse2,"src"),
|
||||
gst_element_get_pad(v_decode,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(v_decode,"src"),
|
||||
gst_element_get_pad(color,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(color,"src"),
|
||||
gst_element_get_pad(show,"sink"));
|
||||
|
||||
// audio
|
||||
gst_pad_connect(gst_element_get_pad(a_queue,"src"),
|
||||
gst_element_get_pad(a_decode,"sink"));
|
||||
gst_pad_connect(gst_element_get_pad(a_decode,"src"),
|
||||
gst_element_get_pad(osssink,"sink"));
|
||||
|
||||
gtk_widget_show_all(appwindow);
|
||||
gtk_signal_connect(GTK_OBJECT(show),"have_size",mpeg2parse_have_size, pipeline);
|
||||
|
||||
g_print("setting to PLAYING state\n");
|
||||
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
|
||||
|
|
224
test/mpeg2parse4.c
Normal file
224
test/mpeg2parse4.c
Normal 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;
|
||||
}
|
|
@ -54,7 +54,6 @@ gst_play_typefind (GstBin *bin, GstElement *element)
|
|||
gst_pad_disconnect (gst_element_get_pad (element, "src"),
|
||||
gst_element_get_pad (typefind, "sink"));
|
||||
gst_bin_remove (bin, typefind);
|
||||
gst_object_unref (GST_OBJECT (typefind));
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
@ -174,6 +173,7 @@ int main(int argc,char *argv[])
|
|||
exit (-1);
|
||||
}
|
||||
|
||||
gst_object_ref (GST_OBJECT (disksrc));
|
||||
gst_bin_remove (GST_BIN (bin), disksrc);
|
||||
gst_object_destroy (GST_OBJECT (bin));
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ main (int argc,char *argv[])
|
|||
|
||||
gnome_init("Videotest","0.0.1",argc,argv);
|
||||
|
||||
bin = gst_bin_new("bin");
|
||||
bin = gst_pipeline_new("pipeline");
|
||||
|
||||
src = gst_elementfactory_make ("v4lsrc", "src");
|
||||
gtk_object_set(GTK_OBJECT(src),"format",9,NULL);
|
||||
|
|
|
@ -2,7 +2,7 @@ SUBDIRS = sched eos
|
|||
|
||||
noinst_PROGRAMS = init loadall simplefake states caps queue registry \
|
||||
paranoia rip mp3encode autoplug props case4 markup load tee autoplug2 autoplug3 \
|
||||
capsconnect padfactory autoplug4
|
||||
capsconnect padfactory autoplug4 incsched reaping threadlock mp1vid
|
||||
|
||||
# we have nothing but apps here, we can do this safely
|
||||
LIBS += $(GST_LIBS)
|
||||
|
|
135
tests/incsched.c
Normal file
135
tests/incsched.c
Normal 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
78
tests/mp1vid.c
Normal 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));
|
||||
}
|
|
@ -8,4 +8,4 @@ endif
|
|||
SUBDIRS = $(GNOME_SUBDS) \
|
||||
helloworld helloworld2 \
|
||||
queue queue2 queue3 queue4 \
|
||||
launch thread xml plugins typefind
|
||||
launch thread xml plugins typefind mixer
|
||||
|
|
|
@ -2,93 +2,35 @@
|
|||
#include <gnome.h>
|
||||
|
||||
static void
|
||||
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
|
||||
autoplug_have_size (GstElement *element, guint width, guint height,
|
||||
GtkWidget *socket)
|
||||
{
|
||||
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
|
||||
|
||||
*(gboolean *)data = TRUE;
|
||||
gtk_widget_set_usize(socket,width,height);
|
||||
}
|
||||
|
||||
gboolean
|
||||
idle_func (gpointer data)
|
||||
static void
|
||||
gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
|
||||
{
|
||||
return gst_bin_iterate (GST_BIN (data));
|
||||
}
|
||||
|
||||
static GstCaps*
|
||||
gst_play_typefind (GstBin *bin, GstElement *element)
|
||||
{
|
||||
gboolean found = FALSE;
|
||||
GstElement *typefind;
|
||||
GstCaps *caps = NULL;
|
||||
|
||||
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
|
||||
GST_ELEMENT_NAME(element), &found);
|
||||
|
||||
typefind = gst_elementfactory_make ("typefind", "typefind");
|
||||
g_return_val_if_fail (typefind != NULL, FALSE);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
|
||||
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
|
||||
|
||||
gst_pad_connect (gst_element_get_pad (element, "src"),
|
||||
gst_element_get_pad (typefind, "sink"));
|
||||
|
||||
gst_bin_add (bin, typefind);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
|
||||
|
||||
// push a buffer... the have_type signal handler will set the found flag
|
||||
gst_bin_iterate (bin);
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
|
||||
|
||||
caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
|
||||
|
||||
gst_pad_disconnect (gst_element_get_pad (element, "src"),
|
||||
gst_element_get_pad (typefind, "sink"));
|
||||
gst_bin_remove (bin, typefind);
|
||||
gst_object_unref (GST_OBJECT (typefind));
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
GstElement *disksrc, *osssink, *videosink;
|
||||
GstElement *bin;
|
||||
GstElement *osssink, *videosink;
|
||||
GtkWidget *appwindow;
|
||||
GstCaps *srccaps;
|
||||
GstElement *new_element;
|
||||
GstAutoplug *autoplug;
|
||||
GtkWidget *socket;
|
||||
GstElement *autobin;
|
||||
GstElement *disksrc;
|
||||
GstElement *cache;
|
||||
|
||||
g_thread_init(NULL);
|
||||
gst_init(&argc,&argv);
|
||||
gnome_init("autoplug","0.0.1", argc,argv);
|
||||
GST_DEBUG (0,"GstPipeline: play have type\n");
|
||||
|
||||
if (argc != 2) {
|
||||
g_print("usage: %s <filename>\n", argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
|
||||
/* create a new bin to hold the elements */
|
||||
bin = gst_pipeline_new("pipeline");
|
||||
g_assert(bin != NULL);
|
||||
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");
|
||||
|
||||
/* 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 (bin), disksrc);
|
||||
|
||||
srccaps = gst_play_typefind (GST_BIN (bin), disksrc);
|
||||
|
||||
if (!srccaps) {
|
||||
g_print ("could not autoplug, unknown media type...\n");
|
||||
exit (-1);
|
||||
}
|
||||
// disconnect the typefind from the pipeline and remove it
|
||||
gst_element_disconnect (cache, "src", typefind, "sink");
|
||||
gst_bin_remove (GST_BIN (autobin), typefind);
|
||||
|
||||
/* and an audio sink */
|
||||
osssink = gst_elementfactory_make("osssink", "play_audio");
|
||||
|
@ -102,7 +44,7 @@ int main(int argc,char *argv[])
|
|||
g_assert (autoplug != NULL);
|
||||
|
||||
new_element = gst_autoplug_to_renderers (autoplug,
|
||||
srccaps,
|
||||
caps,
|
||||
videosink,
|
||||
osssink,
|
||||
NULL);
|
||||
|
@ -112,14 +54,13 @@ int main(int argc,char *argv[])
|
|||
exit (-1);
|
||||
}
|
||||
|
||||
gst_bin_remove (GST_BIN (bin), disksrc);
|
||||
// FIXME hack, reparent the disksrc so the scheduler doesn't break
|
||||
bin = gst_pipeline_new("pipeline");
|
||||
gst_element_set_name (new_element, "new_element");
|
||||
|
||||
gst_bin_add (GST_BIN (bin), disksrc);
|
||||
gst_bin_add (GST_BIN (bin), new_element);
|
||||
gst_bin_add (GST_BIN (autobin), new_element);
|
||||
|
||||
gst_element_connect (disksrc, "src", new_element, "sink");
|
||||
gtk_object_set (GTK_OBJECT (cache), "reset", TRUE, NULL);
|
||||
|
||||
gst_element_connect (cache, "src", new_element, "sink");
|
||||
|
||||
appwindow = gnome_app_new ("autoplug demo","autoplug demo");
|
||||
|
||||
|
@ -132,22 +73,103 @@ int main(int argc,char *argv[])
|
|||
gtk_widget_realize (socket);
|
||||
gtk_socket_steal (GTK_SOCKET (socket),
|
||||
gst_util_get_int_arg (GTK_OBJECT (videosink), "xid"));
|
||||
gtk_widget_set_usize(socket,320,240);
|
||||
|
||||
gtk_widget_show_all (appwindow);
|
||||
|
||||
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 */
|
||||
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_PLAYING);
|
||||
|
||||
gtk_idle_add(idle_func, bin);
|
||||
gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
|
||||
gtk_idle_add (idle_func, pipeline);
|
||||
gst_main ();
|
||||
|
||||
/* stop the bin */
|
||||
gst_element_set_state(GST_ELEMENT(bin), GST_STATE_NULL);
|
||||
/* stop the pipeline */
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
|
||||
|
||||
gst_pipeline_destroy(bin);
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
* demonstrates the adder plugin and the volume envelope plugin
|
||||
* work in progress but do try it out
|
||||
*
|
||||
* Latest change : 16/04/2001
|
||||
* multiple input channels allowed
|
||||
* volume envelope adapted
|
||||
* Version : 0.3
|
||||
* Latest change : 28/04/2001
|
||||
* trying to adapt to incsched
|
||||
* delayed start for channels > 1
|
||||
* now works by quickhacking the
|
||||
* adder plugin to set
|
||||
* GST_ELEMENT_COTHREAD_STOPPING
|
||||
* Version : 0.5
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -15,8 +18,10 @@
|
|||
#include "mixer.h"
|
||||
#include <unistd.h>
|
||||
|
||||
//#define WITH_BUG
|
||||
//#define WITH_BUG2
|
||||
//#define DEBUG
|
||||
|
||||
//#define AUTOPLUG /* define if you want autoplugging of input channels */
|
||||
/* function prototypes */
|
||||
|
||||
input_channel_t* create_input_channel (int id, char* location);
|
||||
|
@ -35,55 +40,50 @@ void eos(GstElement *element)
|
|||
// playing = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_play_have_type (GstElement *sink, GstElement *sink2, gpointer data)
|
||||
{
|
||||
GST_DEBUG (0,"GstPipeline: play have type %p\n", (gboolean *)data);
|
||||
|
||||
*(gboolean *)data = TRUE;
|
||||
}
|
||||
|
||||
static GstCaps*
|
||||
gst_play_typefind (GstBin *bin, GstElement *element)
|
||||
{
|
||||
gboolean found = FALSE;
|
||||
GstElement *typefind;
|
||||
GstElement *pipeline;
|
||||
GstCaps *caps = NULL;
|
||||
|
||||
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\" %p\n",
|
||||
GST_ELEMENT_NAME(element), &found);
|
||||
GST_DEBUG (0,"GstPipeline: typefind for element \"%s\"\n",
|
||||
GST_ELEMENT_NAME(element));
|
||||
|
||||
pipeline = gst_pipeline_new ("autoplug_pipeline");
|
||||
|
||||
typefind = gst_elementfactory_make ("typefind", "typefind");
|
||||
g_return_val_if_fail (typefind != NULL, FALSE);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (typefind), "have_type",
|
||||
GTK_SIGNAL_FUNC (gst_play_have_type), &found);
|
||||
|
||||
gst_pad_connect (gst_element_get_pad (element, "src"),
|
||||
gst_element_get_pad (typefind, "sink"));
|
||||
gst_bin_add (bin, typefind);
|
||||
gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (bin));
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
// push a buffer... the have_type signal handler will set the found flag
|
||||
gst_bin_iterate (bin);
|
||||
gst_bin_iterate (GST_BIN (pipeline));
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
|
||||
|
||||
gst_pad_disconnect (gst_element_get_pad (element, "src"),
|
||||
gst_element_get_pad (typefind, "sink"));
|
||||
gst_bin_remove (bin, typefind);
|
||||
gst_bin_remove (GST_BIN (pipeline), GST_ELEMENT (bin));
|
||||
gst_object_unref (GST_OBJECT (typefind));
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
int num_channels;
|
||||
gboolean done;
|
||||
|
||||
char buffer[20];
|
||||
|
||||
|
@ -114,11 +114,12 @@ int main(int argc,char *argv[])
|
|||
audiosink = gst_elementfactory_make ("esdsink", "play_audio");
|
||||
|
||||
/* create main bin */
|
||||
main_bin = gst_bin_new("bin");
|
||||
main_bin = gst_pipeline_new("bin");
|
||||
|
||||
/* connect adder and output to bin */
|
||||
|
||||
GST_INFO (0, "main: adding adder to bin");
|
||||
gst_bin_add (GST_BIN(main_bin), adder);
|
||||
GST_INFO (0, "main: adding audiosink to bin");
|
||||
gst_bin_add (GST_BIN(main_bin), audiosink);
|
||||
|
||||
/* connect adder and audiosink */
|
||||
|
@ -126,8 +127,7 @@ int main(int argc,char *argv[])
|
|||
gst_pad_connect(gst_element_get_pad(adder,"src"),
|
||||
gst_element_get_pad(audiosink,"sink"));
|
||||
|
||||
/* create input channels, add to bin and connect */
|
||||
|
||||
/* start looping */
|
||||
input_channels = NULL;
|
||||
|
||||
for (i = 1; i < argc; ++i)
|
||||
|
@ -135,11 +135,14 @@ int main(int argc,char *argv[])
|
|||
printf ("Opening channel %d from file %s...\n", i, argv[i]);
|
||||
channel_in = create_input_channel (i, argv[i]);
|
||||
input_channels = g_list_append (input_channels, channel_in);
|
||||
|
||||
if (i > 1) gst_element_set_state (main_bin, GST_STATE_PAUSED);
|
||||
gst_bin_add (GST_BIN(main_bin), channel_in->pipe);
|
||||
|
||||
/* request pads and connect to adder */
|
||||
GST_INFO (0, "requesting pad\n");
|
||||
pad = gst_element_request_pad_by_name (adder, "sink%d");
|
||||
g_print ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
|
||||
printf ("\tGot new adder sink pad %s\n", gst_pad_get_name (pad));
|
||||
sprintf (buffer, "channel%d", i);
|
||||
gst_pad_connect (gst_element_get_pad (channel_in->pipe, buffer), pad);
|
||||
|
||||
|
@ -178,24 +181,32 @@ int main(int argc,char *argv[])
|
|||
env_register_cp (channel_in->volenv, num_channels * 10.0 - 5.0, 0.0000001); /* start fade in */
|
||||
}
|
||||
env_register_cp (channel_in->volenv, num_channels * 10.0 , 1.0 / num_channels); /* to end level */
|
||||
}
|
||||
|
||||
/* sleep a few seconds doesn't seem to help anyway */
|
||||
|
||||
printf ("Sleeping a few seconds ...\n");
|
||||
sleep (2);
|
||||
printf ("Waking up ...\n");
|
||||
|
||||
xmlSaveFile("mixer.xml", gst_xml_write(GST_ELEMENT(main_bin)));
|
||||
|
||||
/* start playing */
|
||||
gst_element_set_state(main_bin, GST_STATE_PLAYING);
|
||||
|
||||
// write out the schedule
|
||||
gst_schedule_show(GST_ELEMENT_SCHED(main_bin));
|
||||
playing = TRUE;
|
||||
|
||||
while (playing) {
|
||||
j = 0;
|
||||
//printf ("main: start iterating from 0");
|
||||
while (playing && j < 100)
|
||||
{
|
||||
// printf ("main: iterating %d\n", j);
|
||||
gst_bin_iterate(GST_BIN(main_bin));
|
||||
//fprintf(stderr,"after iterate()\n");
|
||||
++j;
|
||||
}
|
||||
}
|
||||
printf ("main: all the channels are open\n");
|
||||
while (playing)
|
||||
{
|
||||
gst_bin_iterate(GST_BIN(main_bin));
|
||||
//fprintf(stderr,"after iterate()\n");
|
||||
}
|
||||
|
||||
/* stop the bin */
|
||||
gst_element_set_state(main_bin, GST_STATE_NULL);
|
||||
|
||||
|
@ -228,11 +239,10 @@ create_input_channel (int id, char* location)
|
|||
GstAutoplug *autoplug;
|
||||
GstCaps *srccaps;
|
||||
GstElement *new_element;
|
||||
GstElement *decoder;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("DEBUG : c_i_p : creating channel with id %d for file %s\n",
|
||||
GST_DEBUG (0, "c_i_p : creating channel with id %d for file %s\n",
|
||||
id, location);
|
||||
#endif
|
||||
|
||||
/* allocate channel */
|
||||
|
||||
|
@ -245,23 +255,21 @@ create_input_channel (int id, char* location)
|
|||
|
||||
/* create channel */
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("DEBUG : c_i_p : creating pipeline\n");
|
||||
#endif
|
||||
GST_DEBUG (0, "c_i_p : creating pipeline\n");
|
||||
|
||||
channel->pipe = gst_bin_new ("pipeline");
|
||||
sprintf (buffer, "pipeline%d", id);
|
||||
channel->pipe = gst_bin_new (buffer);
|
||||
g_assert(channel->pipe != NULL);
|
||||
|
||||
/* create elements */
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("DEBUG : c_i_p : creating disksrc\n");
|
||||
#endif
|
||||
GST_DEBUG(0, "c_i_p : creating disksrc\n");
|
||||
|
||||
sprintf (buffer, "disksrc%d", id);
|
||||
channel->disksrc = gst_elementfactory_make ("disksrc", buffer);
|
||||
g_assert(channel->disksrc != NULL);
|
||||
|
||||
GST_DEBUG(0, "c_i_p : setting location\n");
|
||||
gtk_object_set(GTK_OBJECT(channel->disksrc),"location", location, NULL);
|
||||
|
||||
/* add disksrc to the bin before autoplug */
|
||||
|
@ -286,8 +294,24 @@ create_input_channel (int id, char* location)
|
|||
printf ("DEBUG : c_i_p : getting srccaps\n");
|
||||
#endif
|
||||
|
||||
#ifdef WITH_BUG
|
||||
srccaps = gst_play_typefind (GST_BIN (channel->pipe), channel->disksrc);
|
||||
#endif
|
||||
#ifdef WITH_BUG2
|
||||
{
|
||||
GstElement *pipeline;
|
||||
|
||||
pipeline = gst_pipeline_new ("autoplug_pipeline");
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), channel->pipe);
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
gst_bin_remove (GST_BIN (pipeline), channel->pipe);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AUTOPLUG
|
||||
if (!srccaps) {
|
||||
g_print ("could not autoplug, unknown media type...\n");
|
||||
exit (-1);
|
||||
|
@ -312,6 +336,23 @@ create_input_channel (int id, char* location)
|
|||
exit (-1);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
new_element = gst_bin_new ("autoplug_bin");
|
||||
|
||||
/* static plug, use mad plugin and assume mp3 input */
|
||||
decoder = gst_elementfactory_make ("mad", "mpg123");
|
||||
|
||||
gst_bin_add (GST_BIN (new_element), decoder);
|
||||
|
||||
gst_element_add_ghost_pad (new_element,
|
||||
gst_element_get_pad (decoder, "sink"), "sink");
|
||||
gst_element_add_ghost_pad (new_element,
|
||||
gst_element_get_pad (decoder, "src"), "src_00");
|
||||
|
||||
#endif
|
||||
xmlSaveFile ("mixer.gst", gst_xml_write (new_element));
|
||||
|
||||
gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
|
||||
gst_bin_add (GST_BIN (channel->pipe), new_element);
|
||||
|
||||
|
|
18
tests/old/testsuite/refcounting/Makefile.am
Normal file
18
tests/old/testsuite/refcounting/Makefile.am
Normal 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
tests/old/testsuite/refcounting/bin.c
Normal file
272
tests/old/testsuite/refcounting/bin.c
Normal 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);
|
||||
}
|
116
tests/old/testsuite/refcounting/element.c
Normal file
116
tests/old/testsuite/refcounting/element.c
Normal 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);
|
||||
}
|
134
tests/old/testsuite/refcounting/element_pad.c
Normal file
134
tests/old/testsuite/refcounting/element_pad.c
Normal 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);
|
||||
}
|
22
tests/old/testsuite/refcounting/mem.c
Normal file
22
tests/old/testsuite/refcounting/mem.c
Normal 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;
|
||||
}
|
1
tests/old/testsuite/refcounting/mem.h
Normal file
1
tests/old/testsuite/refcounting/mem.h
Normal file
|
@ -0,0 +1 @@
|
|||
int vmsize();
|
156
tests/old/testsuite/refcounting/object.c
Normal file
156
tests/old/testsuite/refcounting/object.c
Normal 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);
|
||||
}
|
223
tests/old/testsuite/refcounting/pad.c
Normal file
223
tests/old/testsuite/refcounting/pad.c
Normal 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;
|
||||
}
|
281
tests/old/testsuite/refcounting/thread.c
Normal file
281
tests/old/testsuite/refcounting/thread.c
Normal 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
35
tests/reaping.c
Normal 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);
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
gboolean state_change(GstElement *element,GstElementState state) {
|
||||
g_print(">STATES: element '%s' state set to %d(%s)\n",
|
||||
gst_element_get_name(element),state,_gst_print_statename(state));
|
||||
gst_element_get_name(element),state,gst_element_statename(state));
|
||||
g_print(">STATES: element state is actually %d\n",GST_STATE(element));
|
||||
|
||||
return TRUE;
|
||||
|
@ -37,15 +37,15 @@ int main(int argc,char *argv[]) {
|
|||
GTK_SIGNAL_FUNC(state_change),NULL);
|
||||
|
||||
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(src),
|
||||
GST_STATE(src),_gst_print_statename(GST_STATE(src)));
|
||||
GST_STATE(src),gst_element_statename(GST_STATE(src)));
|
||||
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(subbin),
|
||||
GST_STATE(subbin),_gst_print_statename(GST_STATE(subbin)));
|
||||
GST_STATE(subbin),gst_element_statename(GST_STATE(subbin)));
|
||||
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(filter),
|
||||
GST_STATE(filter),_gst_print_statename(GST_STATE(filter)));
|
||||
GST_STATE(filter),gst_element_statename(GST_STATE(filter)));
|
||||
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(sink),
|
||||
GST_STATE(sink),_gst_print_statename(GST_STATE(sink)));
|
||||
GST_STATE(sink),gst_element_statename(GST_STATE(sink)));
|
||||
g_print("STATES: element '%s' starts at state %d(%s)\n",gst_element_get_name(bin),
|
||||
GST_STATE(bin),_gst_print_statename(GST_STATE(bin)));
|
||||
GST_STATE(bin),gst_element_statename(GST_STATE(bin)));
|
||||
|
||||
gst_bin_add(GST_BIN(subbin),filter);
|
||||
gst_element_add_ghost_pad(GST_ELEMENT(bin),gst_element_get_pad(filter,"sink"),"sink");
|
||||
|
|
51
tests/threadlock.c
Normal file
51
tests/threadlock.c
Normal 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);
|
||||
}
|
18
testsuite/refcounting/Makefile.am
Normal file
18
testsuite/refcounting/Makefile.am
Normal 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
272
testsuite/refcounting/bin.c
Normal 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);
|
||||
}
|
116
testsuite/refcounting/element.c
Normal file
116
testsuite/refcounting/element.c
Normal 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);
|
||||
}
|
134
testsuite/refcounting/element_pad.c
Normal file
134
testsuite/refcounting/element_pad.c
Normal 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);
|
||||
}
|
22
testsuite/refcounting/mem.c
Normal file
22
testsuite/refcounting/mem.c
Normal 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;
|
||||
}
|
1
testsuite/refcounting/mem.h
Normal file
1
testsuite/refcounting/mem.h
Normal file
|
@ -0,0 +1 @@
|
|||
int vmsize();
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue