mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-12 11:26:39 +00:00
First round of incremental scheduling. Manager setting and managed_elements lists are now handled at bin_add/remove ...
Original commit message from CVS: First round of incremental scheduling. Manager setting and managed_elements lists are now handled at bin_add/remove time. Scheduling chains can be created incrementally as well, though there are still some pieces missing.
This commit is contained in:
parent
d0d6cd30d4
commit
8edfe3f5de
24 changed files with 473 additions and 397 deletions
11
Makefile.am
11
Makefile.am
|
@ -8,17 +8,10 @@ else
|
||||||
SUBDIRS_LGG =
|
SUBDIRS_LGG =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_DOCS
|
SUBDIRS = include gst libs plugins tools test tests examples $(SUBDIRS_LGG) docs
|
||||||
SUBDIRS_DOCS = docs
|
|
||||||
else
|
|
||||||
SUBDIRS_DOCS =
|
|
||||||
endif
|
|
||||||
|
|
||||||
SUBDIRS = include gst libs plugins tools test tests examples \
|
|
||||||
$(SUBDIRS_LGG) $(SUBDIRS_DOCS)
|
|
||||||
|
|
||||||
# These are all the possible subdirs
|
# These are all the possible subdirs
|
||||||
DIST_SUBDIRS = include gst libs plugins tools test tests examples gstplay editor docs
|
DIST_SUBDIRS = intl po include gst libs plugins tools test tests examples gstplay editor docs
|
||||||
|
|
||||||
|
|
||||||
bin_SCRIPTS = gstreamer-config
|
bin_SCRIPTS = gstreamer-config
|
||||||
|
|
16
configure.in
16
configure.in
|
@ -50,6 +50,9 @@ AM_DISABLE_STATIC
|
||||||
AC_LIBTOOL_DLOPEN
|
AC_LIBTOOL_DLOPEN
|
||||||
AM_PROG_LIBTOOL
|
AM_PROG_LIBTOOL
|
||||||
|
|
||||||
|
dnl ALL_LINGUAS=""
|
||||||
|
dnl AM_GNU_GETTEXT
|
||||||
|
|
||||||
CFLAGS=""
|
CFLAGS=""
|
||||||
|
|
||||||
dnl ##############################
|
dnl ##############################
|
||||||
|
@ -484,16 +487,6 @@ AC_ARG_WITH(win32_libdir,
|
||||||
esac],
|
esac],
|
||||||
[:]) dnl Default value
|
[:]) dnl Default value
|
||||||
|
|
||||||
AC_ARG_ENABLE(docs-build,
|
|
||||||
[ --enable-docs-build enable the building of the 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=no]) dnl Default value
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dnl ################################################
|
dnl ################################################
|
||||||
dnl # Set defines according to variables set above #
|
dnl # Set defines according to variables set above #
|
||||||
|
@ -571,7 +564,6 @@ AM_CONDITIONAL(HAVE_LIBGLADE_GNOME, test "x$HAVE_LIBGLADE_GNOME" = "xyes")
|
||||||
AM_CONDITIONAL(HAVE_GNOME, test "x$HAVE_GNOME" = "xyes")
|
AM_CONDITIONAL(HAVE_GNOME, test "x$HAVE_GNOME" = "xyes")
|
||||||
AM_CONDITIONAL(HAVE_LIBXV, test "x$HAVE_LIBXV" = "xyes")
|
AM_CONDITIONAL(HAVE_LIBXV, test "x$HAVE_LIBXV" = "xyes")
|
||||||
AM_CONDITIONAL(HAVE_GTK_DOC, $HAVE_GTK_DOC)
|
AM_CONDITIONAL(HAVE_GTK_DOC, $HAVE_GTK_DOC)
|
||||||
AM_CONDITIONAL(BUILD_DOCS, test "x$BUILD_DOCS" = "xyes")
|
|
||||||
AM_CONDITIONAL(HAVE_DB2HTML, $HAVE_DB2HTML)
|
AM_CONDITIONAL(HAVE_DB2HTML, $HAVE_DB2HTML)
|
||||||
AM_CONDITIONAL(HAVE_DB2PS, $HAVE_DB2PS)
|
AM_CONDITIONAL(HAVE_DB2PS, $HAVE_DB2PS)
|
||||||
AM_CONDITIONAL(HAVE_PS2PDF, $HAVE_PS2PDF)
|
AM_CONDITIONAL(HAVE_PS2PDF, $HAVE_PS2PDF)
|
||||||
|
@ -656,6 +648,8 @@ dnl # Make the output files #
|
||||||
dnl #########################
|
dnl #########################
|
||||||
|
|
||||||
AC_OUTPUT([Makefile
|
AC_OUTPUT([Makefile
|
||||||
|
intl/Makefile
|
||||||
|
po/Makefile.in
|
||||||
include/Makefile
|
include/Makefile
|
||||||
include/wine/Makefile
|
include/wine/Makefile
|
||||||
gst/Makefile
|
gst/Makefile
|
||||||
|
|
Binary file not shown.
|
@ -1,277 +0,0 @@
|
||||||
caps negotiation
|
|
||||||
================
|
|
||||||
|
|
||||||
1) purpose
|
|
||||||
----------
|
|
||||||
|
|
||||||
The pads expose the media types they can handle using a mime
|
|
||||||
type and a set of properties. Before the pad is created or
|
|
||||||
used to pass buffers, we only know the global 'range' of media
|
|
||||||
data this pad can accept. When the element has had a chance to
|
|
||||||
look at the media data, only then it knows the exact values of the
|
|
||||||
properties.
|
|
||||||
|
|
||||||
example1:
|
|
||||||
!
|
|
||||||
! The mp3 decoder exposes the capabilities of its src pad
|
|
||||||
! with the following caps:
|
|
||||||
!
|
|
||||||
! 'mpg123_src':
|
|
||||||
! MIME type: 'audio/raw':
|
|
||||||
! format: Integer: 16
|
|
||||||
! depth: Integer: 16
|
|
||||||
! rate: Integer range: 11025 - 48000
|
|
||||||
! channels: Integer range: 1 - 2
|
|
||||||
|
|
||||||
as you can see in example1, the padtemplate has both a range
|
|
||||||
(for the audio rate) and a list (for the number of channels)
|
|
||||||
for its properties.
|
|
||||||
|
|
||||||
only when the mpg123 element has decoded the first mpeg audio
|
|
||||||
header, it knows the exact values of the rate and channels
|
|
||||||
properties.
|
|
||||||
|
|
||||||
suppose that we want to connect this src pad to the sink pad
|
|
||||||
of an audiosink with the properties given in example2:
|
|
||||||
|
|
||||||
example2:
|
|
||||||
!
|
|
||||||
! 'audiosink_sink':
|
|
||||||
! MIME type: 'audio/raw':
|
|
||||||
! format: Integer: 16
|
|
||||||
! depth: List:
|
|
||||||
! Integer: 8
|
|
||||||
! Integer: 16
|
|
||||||
! rate: Integer range: 8000 - 44000
|
|
||||||
! channels: Integer range: 1 - 2
|
|
||||||
|
|
||||||
we can see that connecting the mpg123 src pad with the
|
|
||||||
audiosinks sink pad can cause a potential problem with the
|
|
||||||
rate property.
|
|
||||||
|
|
||||||
When the mpg123 decoder decides to output raw audio with a
|
|
||||||
48000Hz samplerate, the audiosink will not be able to handle
|
|
||||||
it. The conservative approach would be to disallow the connection
|
|
||||||
between the two incompatible pads. This rules out any potential
|
|
||||||
problems but severely limits the amount of possible connections
|
|
||||||
between the elements.
|
|
||||||
|
|
||||||
Another approach would be to allow the connection (and mark it
|
|
||||||
as dangerous) and let the two elements figure out a suitable
|
|
||||||
media type at runtime. This procedure is called caps negotiation.
|
|
||||||
|
|
||||||
|
|
||||||
2) a bit of history
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
The typing of the data that was attached to a buffer used to be
|
|
||||||
done using GstMeta* (and it still is as of 11 feb 2001). With
|
|
||||||
the new GstCaps and GstProps system this typing is gradually moved
|
|
||||||
to the pads and to the padtemplates. This has several advantages:
|
|
||||||
|
|
||||||
- the typing of the data tends to be static. The type of media
|
|
||||||
doesn't change for every buffer.
|
|
||||||
|
|
||||||
- Moving the typing up to the pad(templates) allows us to save
|
|
||||||
them into the registry and allows us to figure out what pads
|
|
||||||
are compatible.
|
|
||||||
|
|
||||||
- the current metadata implementation needs header files. this may
|
|
||||||
change when we also use properties for metadata.
|
|
||||||
|
|
||||||
example3:
|
|
||||||
!
|
|
||||||
! This is the current GstMeta structure that travels with audio buffers
|
|
||||||
!
|
|
||||||
! struct _MetaAudioRaw {
|
|
||||||
! GstMeta meta;
|
|
||||||
!
|
|
||||||
! /* formatting information */
|
|
||||||
! gint format;
|
|
||||||
! gint channels;
|
|
||||||
! gint frequency;
|
|
||||||
! gint bps;
|
|
||||||
! };
|
|
||||||
|
|
||||||
|
|
||||||
The question still remains what purpose the metadata will serve
|
|
||||||
now that we expose the media type in the pads. Some possibilities:
|
|
||||||
|
|
||||||
- interesting information, not describing the data itself but the
|
|
||||||
context in which the data was generated (suggested buffer size,
|
|
||||||
timestamps, etc...)
|
|
||||||
|
|
||||||
- user app metadata.
|
|
||||||
|
|
||||||
In this proposal we also assume that the current use of metadata using
|
|
||||||
GstMeta is deprecated and that we move this information to the properties
|
|
||||||
of the pads.
|
|
||||||
|
|
||||||
|
|
||||||
3) the pad/padtemplates caps
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
All elements have to provide a padtemplate for their pads.
|
|
||||||
|
|
||||||
The padtemplates provide a range of possible media types this pad can
|
|
||||||
src/sink. the main purpose for the padtemplates is to allow a
|
|
||||||
rough guess at which pads are compatible before even a single buffer
|
|
||||||
has been processed by the element.
|
|
||||||
|
|
||||||
pads are usually created from the templates. When the pad is created
|
|
||||||
it has no GstCaps* attached to it yet. The possible caps this pad
|
|
||||||
can have is exposed in the padtemplate.
|
|
||||||
|
|
||||||
|
|
||||||
4) the connect function
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
when two pads are connected the following steps will take
|
|
||||||
place:
|
|
||||||
|
|
||||||
- if both pads have caps, the caps are checked. If the caps
|
|
||||||
are incompatible, the padtemplates are checked, if they
|
|
||||||
are compatible, caps negotiation is performed.
|
|
||||||
|
|
||||||
- if one of the pads has caps, the caps is checked against
|
|
||||||
the padtemplate of the peer pad. If they are incompatible,
|
|
||||||
the padtemplates are compared, if they are incompatible,
|
|
||||||
caps negotiation is performed.
|
|
||||||
|
|
||||||
- if none of the pads have caps, the padtemplates are checked,
|
|
||||||
if they are incompatible, a warning is issued.
|
|
||||||
|
|
||||||
|
|
||||||
5) when the element knows the media type it is handling
|
|
||||||
-------------------------------------------------------
|
|
||||||
|
|
||||||
When the element has received its first buffer it will know
|
|
||||||
the media type it is handling by inspecting the buffer.
|
|
||||||
|
|
||||||
before pushing the data out to its peer element(s), the element
|
|
||||||
will set its src pad with the appropriate caps and properties.
|
|
||||||
These caps must follow the following rules:
|
|
||||||
|
|
||||||
- the caps must be compatible with the padtemplates of this
|
|
||||||
pad.
|
|
||||||
|
|
||||||
- the caps cannot contain ranges or lists.
|
|
||||||
|
|
||||||
by setting the caps of the src pad, the following procedure
|
|
||||||
happens:
|
|
||||||
|
|
||||||
- if the peer pad has a negotiate function, it is called and
|
|
||||||
negotiation is performed (see later)
|
|
||||||
|
|
||||||
- if the peer pad has no negotiate function, the padtemplate
|
|
||||||
is checked:
|
|
||||||
|
|
||||||
- if the caps are compatible with the template, the peer pad
|
|
||||||
receives the same caps as the src pad.
|
|
||||||
|
|
||||||
- if the caps are not compatible, the negotiation fails and
|
|
||||||
the elements are disconnected. A signal is emitted to inform
|
|
||||||
the user app or the manager of the element to find a solution.
|
|
||||||
|
|
||||||
the caps can be set with the gst_pad_set_caps function, which accepts
|
|
||||||
the following parameters:
|
|
||||||
|
|
||||||
- the pad to set the caps to
|
|
||||||
- a GstCaps* structure
|
|
||||||
|
|
||||||
example4:
|
|
||||||
!
|
|
||||||
! an audio element setting its src pad caps (need something easier):
|
|
||||||
!
|
|
||||||
! gst_pad_set_caps (
|
|
||||||
! pad,
|
|
||||||
! gst_caps_new_with_props (
|
|
||||||
! "src_caps", /* name */
|
|
||||||
! "audio/raw", /* mime */
|
|
||||||
! gst_props_new (
|
|
||||||
! "format", GST_PROPS_INT (AFMT_S16_LE),
|
|
||||||
! "depth", GST_PROPS_INT (16),
|
|
||||||
! "rate", GST_PROPS_INT (44100),
|
|
||||||
! "channels", GST_PROPS_INT (2),
|
|
||||||
! NULL
|
|
||||||
! )
|
|
||||||
! )
|
|
||||||
! );
|
|
||||||
|
|
||||||
The _set_caps method will trigger the caps negotiation with the
|
|
||||||
peer pad (if connected).
|
|
||||||
|
|
||||||
|
|
||||||
6) caps negotiation function
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
the negotiate function of a pad is called whenever the peer pad
|
|
||||||
modifies the caps using the gst_pad_set_caps function.
|
|
||||||
|
|
||||||
The negotiate function has to return a gboolean indicating the
|
|
||||||
new caps are acceptable. When it accepts the caps, both pads will
|
|
||||||
be set to the negotiated caps.
|
|
||||||
|
|
||||||
example5:
|
|
||||||
!
|
|
||||||
! this is the caps negotiation function implemented by an element on
|
|
||||||
! one of its sink pads.
|
|
||||||
!
|
|
||||||
! static gboolean
|
|
||||||
! gst_pad_caps_negotiate (GstPad *pad, GstCaps *caps)
|
|
||||||
! {
|
|
||||||
! /* we don't accept anything else than audio/raw */
|
|
||||||
! if (strcmp (gst_caps_get_mime (caps), "audio/raw"))
|
|
||||||
! return FALSE;
|
|
||||||
!
|
|
||||||
! if (gst_caps_get_int_prop (caps, "format") != AFMT_S16_LE)
|
|
||||||
! return FALSE;
|
|
||||||
!
|
|
||||||
! /* we accept everything else */
|
|
||||||
! return TRUE;
|
|
||||||
! }
|
|
||||||
|
|
||||||
When the negotiate function returns FALSE (it does not accept the
|
|
||||||
specified caps of the peer pad),
|
|
||||||
|
|
||||||
|
|
||||||
figure1
|
|
||||||
!
|
|
||||||
!
|
|
||||||
! element pad pad->peer
|
|
||||||
! !
|
|
||||||
! ! _negotiate(pad)
|
|
||||||
! !------------------>!
|
|
||||||
! ! gst_pad_negotiate()
|
|
||||||
! !------.
|
|
||||||
! !<-----'
|
|
||||||
! ! _caps_negotiate()
|
|
||||||
! !--------------------->!
|
|
||||||
!
|
|
||||||
!
|
|
||||||
|
|
||||||
|
|
||||||
the element has some of its internal properties changed. It wants
|
|
||||||
to renegotiate the caps with its peer element. The element does:
|
|
||||||
|
|
||||||
gst_pad_renegotiate (element->srcpad);
|
|
||||||
|
|
||||||
this will trigger the class method of the pad and
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
7) use cases
|
|
||||||
------------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,48 +43,29 @@ libgst_la_SOURCES = \
|
||||||
gstparse.c \
|
gstparse.c \
|
||||||
$(GSTARCH_SRCS)
|
$(GSTARCH_SRCS)
|
||||||
|
|
||||||
|
|
||||||
##### Oh this sucks so badly. This isn't funny. #####
|
|
||||||
|
|
||||||
# the compiler shoots cothreads.c in the head at -O6
|
# the compiler shoots cothreads.c in the head at -O6
|
||||||
# FIXME: these manual rules break the dependency generation, so we have a
|
# FIXME: these manual rules break the dependency generation, so we have a
|
||||||
# nasty hack here.
|
# nasty hack here.
|
||||||
#LTCOMPILE2=$(LTCOMPILE) -O2
|
LTCOMPILE2=$(LTCOMPILE) -O2
|
||||||
#COMPILE2=$(COMPILE) -O2
|
COMPILE2=$(COMPILE) -O2
|
||||||
|
cothreads.lo: cothreads.c
|
||||||
cothreads.lo: cothreads.c cothreads.h gst_private.h ../config.h gstinfo.c \
|
@echo '$(LTCOMPILE2) -c $<'; \
|
||||||
gstarch.h gsti386.h
|
$(LTCOMPILE2) -Wp,-MD,.deps/$(*F).pp -c $<
|
||||||
$(LIBTOOL) --mode=compile $(COMPILE) -O2 -c $<
|
@-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
|
||||||
cothreads.o: cothreads.c cothreads.h gst_private.h ../config.h gstinfo.c \
|
< .deps/$(*F).pp > .deps/$(*F).P; \
|
||||||
gstarch.h gsti386.h
|
tr ' ' '\012' < .deps/$(*F).pp \
|
||||||
$(COMPILE) -O2 -c $<
|
| sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
|
||||||
|
>> .deps/$(*F).P; \
|
||||||
# NOTDEPEND.cothreads.lo: cothreads.c
|
rm -f .deps/$(*F).pp
|
||||||
# NOTDEPEND $(LTCOMPILE2) -c $<
|
cothreads.o: cothreads.c
|
||||||
# NOTDEPEND.cothreads.o: cothreads.c
|
@echo '$(COMPILE2) -c $<'; \
|
||||||
# NOTDEPEND $(COMPILE2) -c $<
|
$(COMPILE2) -Wp,-MD,.deps/$(*F).pp -c $<
|
||||||
|
@-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
|
||||||
#cothreads.lo: cothreads.c
|
< .deps/$(*F).pp > .deps/$(*F).P; \
|
||||||
# @echo '$(LTCOMPILE2) -c $<'; \
|
tr ' ' '\012' < .deps/$(*F).pp \
|
||||||
# $(LTCOMPILE2) -Wp,-MD,.deps/$(*F).pp -c $<
|
| sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
|
||||||
# @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
|
>> .deps/$(*F).P; \
|
||||||
# < .deps/$(*F).pp > .deps/$(*F).P; \
|
rm -f .deps/$(*F).pp
|
||||||
# tr ' ' '\012' < .deps/$(*F).pp \
|
|
||||||
# | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
|
|
||||||
# >> .deps/$(*F).P; \
|
|
||||||
# rm -f .deps/$(*F).pp
|
|
||||||
#cothreads.o: cothreads.c
|
|
||||||
# @echo '$(COMPILE2) -c $<'; \
|
|
||||||
# $(COMPILE2) -Wp,-MD,.deps/$(*F).pp -c $<
|
|
||||||
# @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
|
|
||||||
# < .deps/$(*F).pp > .deps/$(*F).P; \
|
|
||||||
# tr ' ' '\012' < .deps/$(*F).pp \
|
|
||||||
# | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
|
|
||||||
# >> .deps/$(*F).P; \
|
|
||||||
# rm -f .deps/$(*F).pp
|
|
||||||
|
|
||||||
##### end immense suckage #####
|
|
||||||
|
|
||||||
|
|
||||||
libgstincludedir = $(includedir)/gst
|
libgstincludedir = $(includedir)/gst
|
||||||
libgstinclude_HEADERS = \
|
libgstinclude_HEADERS = \
|
||||||
|
|
|
@ -263,7 +263,7 @@ cothread_switch (cothread_state *thread)
|
||||||
if (current == thread) goto selfswitch;
|
if (current == thread) goto selfswitch;
|
||||||
|
|
||||||
// find the number of the thread to switch to
|
// find the number of the thread to switch to
|
||||||
GST_INFO (GST_CAT_COTHREAD_SWITCH,"switching from cothread %d to to cothread #%d",
|
GST_INFO (GST_CAT_COTHREAD_SWITCH,"switching from cothread #%d to cothread #%d",
|
||||||
ctx->current,thread->threadnum);
|
ctx->current,thread->threadnum);
|
||||||
ctx->current = thread->threadnum;
|
ctx->current = thread->threadnum;
|
||||||
|
|
||||||
|
|
125
gst/gstbin.c
125
gst/gstbin.c
|
@ -155,6 +155,85 @@ gst_bin_new (const gchar *name)
|
||||||
return gst_elementfactory_make ("bin", name);
|
return gst_elementfactory_make ("bin", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
gst_bin_reset_element_manager (GstElement *element, GstElement *manager)
|
||||||
|
{
|
||||||
|
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "resetting element's manager");
|
||||||
|
|
||||||
|
// first remove the element from its current manager, if any
|
||||||
|
if (element->manager)
|
||||||
|
gst_bin_remove_managed_element (GST_BIN(element->manager), element);
|
||||||
|
// then set the new manager
|
||||||
|
gst_element_set_manager (element,manager);
|
||||||
|
// and add it to the new manager's list
|
||||||
|
if (manager)
|
||||||
|
gst_bin_add_managed_element (GST_BIN(manager), element);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_bin_set_element_manager (GstElement *element,GstElement *manager)
|
||||||
|
{
|
||||||
|
GstElement *realmanager = NULL;
|
||||||
|
GList *children;
|
||||||
|
GstElement *child;
|
||||||
|
|
||||||
|
g_return_if_fail (element != NULL);
|
||||||
|
g_return_if_fail (GST_IS_ELEMENT(element));
|
||||||
|
|
||||||
|
// figure out which element is the manager
|
||||||
|
if (manager) {
|
||||||
|
if (GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
|
||||||
|
realmanager = element;
|
||||||
|
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting children's manager to self");
|
||||||
|
} else {
|
||||||
|
realmanager = manager;
|
||||||
|
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting children's manager to parent");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "unsetting children's manager");
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it's actually a Bin
|
||||||
|
if (GST_IS_BIN(element)) {
|
||||||
|
// set the children's manager
|
||||||
|
children = GST_BIN(element)->children;
|
||||||
|
while (children) {
|
||||||
|
child = GST_ELEMENT (children->data);
|
||||||
|
children = g_list_next(children);
|
||||||
|
|
||||||
|
gst_bin_set_element_manager (child, realmanager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, if it's just a regular old element
|
||||||
|
} else {
|
||||||
|
// simply reset the element's manager
|
||||||
|
gst_bin_reset_element_manager (element, realmanager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_bin_add_managed_element (GstBin *bin, GstElement *element)
|
||||||
|
{
|
||||||
|
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "adding managed element \"%s\"", GST_ELEMENT_NAME(element));
|
||||||
|
bin->managed_elements = g_list_prepend (bin->managed_elements, element);
|
||||||
|
bin->num_managed_elements++;
|
||||||
|
|
||||||
|
gst_schedule_add_element (NULL, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_bin_remove_managed_element (GstBin *bin, GstElement *element)
|
||||||
|
{
|
||||||
|
if (g_list_find (bin->managed_elements, element)) {
|
||||||
|
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "removing managed element %s", GST_ELEMENT_NAME(element));
|
||||||
|
bin->managed_elements = g_list_remove (bin->managed_elements, element);
|
||||||
|
bin->num_managed_elements--;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_schedule_remove_element (NULL, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_bin_add:
|
* gst_bin_add:
|
||||||
* @bin: #GstBin to add element to
|
* @bin: #GstBin to add element to
|
||||||
|
@ -172,15 +251,27 @@ gst_bin_add (GstBin *bin,
|
||||||
g_return_if_fail (element != NULL);
|
g_return_if_fail (element != NULL);
|
||||||
g_return_if_fail (GST_IS_ELEMENT (element));
|
g_return_if_fail (GST_IS_ELEMENT (element));
|
||||||
|
|
||||||
|
GST_DEBUG_ENTER ("");
|
||||||
|
|
||||||
// must be NULL or PAUSED state in order to modify bin
|
// must be NULL or PAUSED state in order to modify bin
|
||||||
|
// FIXME this isn't right any more
|
||||||
g_return_if_fail ((GST_STATE (bin) == GST_STATE_NULL) ||
|
g_return_if_fail ((GST_STATE (bin) == GST_STATE_NULL) ||
|
||||||
(GST_STATE (bin) == GST_STATE_PAUSED));
|
(GST_STATE (bin) == GST_STATE_PAUSED));
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
|
||||||
bin->children = g_list_append (bin->children, element);
|
bin->children = g_list_append (bin->children, element);
|
||||||
bin->numchildren++;
|
bin->numchildren++;
|
||||||
gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
|
|
||||||
|
|
||||||
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child %s", GST_ELEMENT_NAME (element));
|
///// now we have to deal with manager stuff
|
||||||
|
gst_bin_set_element_manager (element, GST_ELEMENT(bin));
|
||||||
|
|
||||||
|
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child \"%s\"", GST_ELEMENT_NAME (element));
|
||||||
|
|
||||||
/* we know we have at least one child, we just added one... */
|
/* we know we have at least one child, we just added one... */
|
||||||
// if (GST_STATE(element) < GST_STATE_READY)
|
// if (GST_STATE(element) < GST_STATE_READY)
|
||||||
|
@ -210,12 +301,20 @@ gst_bin_remove (GstBin *bin,
|
||||||
g_return_if_fail ((GST_STATE (bin) == GST_STATE_NULL) ||
|
g_return_if_fail ((GST_STATE (bin) == GST_STATE_NULL) ||
|
||||||
(GST_STATE (bin) == GST_STATE_PAUSED));
|
(GST_STATE (bin) == GST_STATE_PAUSED));
|
||||||
|
|
||||||
|
// the element must have its parent set to the current bin
|
||||||
|
g_return_if_fail (GST_ELEMENT_PARENT(element) == bin);
|
||||||
|
|
||||||
|
// the element must be in the bin's list of children
|
||||||
if (g_list_find(bin->children, element) == NULL) {
|
if (g_list_find(bin->children, element) == NULL) {
|
||||||
// FIXME this should be a warning!!!
|
// FIXME this should be a warning!!!
|
||||||
GST_ERROR_OBJECT(bin,element,"no such element in bin");
|
GST_ERROR_OBJECT(bin,element,"no such element in bin");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove this element from the list of managed elements
|
||||||
|
gst_bin_set_element_manager (element, NULL);
|
||||||
|
|
||||||
|
// now remove the element from the list of elements
|
||||||
gst_object_unparent (GST_OBJECT (element));
|
gst_object_unparent (GST_OBJECT (element));
|
||||||
bin->children = g_list_remove (bin->children, element);
|
bin->children = g_list_remove (bin->children, element);
|
||||||
bin->numchildren--;
|
bin->numchildren--;
|
||||||
|
@ -286,9 +385,13 @@ gst_bin_change_state (GstElement *element)
|
||||||
// g_print("\n");
|
// g_print("\n");
|
||||||
children = g_list_next (children);
|
children = g_list_next (children);
|
||||||
}
|
}
|
||||||
// g_print("<-- \"%s\"\n",gst_object_get_name(GST_OBJECT(bin)));
|
// g_print("<-- \"%s\"\n",GST_OBJECT_NAME(bin));
|
||||||
|
|
||||||
|
|
||||||
|
GST_INFO_ELEMENT (GST_CAT_STATES, element, "done changing bin's state from %s to %s",
|
||||||
|
_gst_print_statename (GST_STATE (element)),
|
||||||
|
_gst_print_statename (GST_STATE_PENDING (element)));
|
||||||
|
|
||||||
return gst_bin_change_state_norecurse (bin);
|
return gst_bin_change_state_norecurse (bin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +415,7 @@ gst_bin_change_state_type(GstBin *bin,
|
||||||
GstElement *child;
|
GstElement *child;
|
||||||
|
|
||||||
// g_print("gst_bin_change_state_type(\"%s\",%d,%d);\n",
|
// g_print("gst_bin_change_state_type(\"%s\",%d,%d);\n",
|
||||||
// gst_object_get_name(GST_OBJECT(bin)),state,type);
|
// GST_OBJECT_NAME(bin))),state,type);
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
|
g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
|
||||||
g_return_val_if_fail (bin->numchildren != 0, FALSE);
|
g_return_val_if_fail (bin->numchildren != 0, FALSE);
|
||||||
|
@ -411,7 +514,7 @@ gst_bin_get_by_name (GstBin *bin,
|
||||||
children = bin->children;
|
children = bin->children;
|
||||||
while (children) {
|
while (children) {
|
||||||
child = GST_ELEMENT (children->data);
|
child = GST_ELEMENT (children->data);
|
||||||
if (!strcmp (gst_object_get_name (GST_OBJECT (child)),name))
|
if (!strcmp (GST_OBJECT_NAME(child),name))
|
||||||
return child;
|
return child;
|
||||||
if (GST_IS_BIN (child)) {
|
if (GST_IS_BIN (child)) {
|
||||||
GstElement *res = gst_bin_get_by_name (GST_BIN (child), name);
|
GstElement *res = gst_bin_get_by_name (GST_BIN (child), name);
|
||||||
|
@ -635,6 +738,7 @@ gst_bin_create_plan_func (GstBin *bin)
|
||||||
|
|
||||||
GST_INFO_ELEMENT (GST_CAT_PLANNING, bin, "creating plan");
|
GST_INFO_ELEMENT (GST_CAT_PLANNING, bin, "creating plan");
|
||||||
|
|
||||||
|
/*
|
||||||
// first figure out which element is the manager of this and all child elements
|
// 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 we're a managing bin ourselves, that'd be us
|
||||||
if (GST_FLAG_IS_SET (bin, GST_BIN_FLAG_MANAGER)) {
|
if (GST_FLAG_IS_SET (bin, GST_BIN_FLAG_MANAGER)) {
|
||||||
|
@ -651,6 +755,7 @@ gst_bin_create_plan_func (GstBin *bin)
|
||||||
GST_DEBUG (0,"setting manager to \"%s\"\n", GST_ELEMENT_NAME (manager));
|
GST_DEBUG (0,"setting manager to \"%s\"\n", GST_ELEMENT_NAME (manager));
|
||||||
}
|
}
|
||||||
gst_element_set_manager (GST_ELEMENT (bin), manager);
|
gst_element_set_manager (GST_ELEMENT (bin), manager);
|
||||||
|
*/
|
||||||
|
|
||||||
// perform the first recursive pass of plan generation
|
// perform the first recursive pass of plan generation
|
||||||
// we set the manager of every element but those who manage themselves
|
// we set the manager of every element but those who manage themselves
|
||||||
|
@ -669,9 +774,9 @@ gst_bin_create_plan_func (GstBin *bin)
|
||||||
#endif
|
#endif
|
||||||
GST_DEBUG (0,"have element \"%s\"\n",elementname);
|
GST_DEBUG (0,"have element \"%s\"\n",elementname);
|
||||||
|
|
||||||
// first set their manager
|
// // first set their manager
|
||||||
GST_DEBUG (0,"setting manager of \"%s\" to \"%s\"\n",elementname,GST_ELEMENT_NAME (manager));
|
// GST_DEBUG (0,"setting manager of \"%s\" to \"%s\"\n",elementname,GST_ELEMENT_NAME (manager));
|
||||||
gst_element_set_manager (element, manager);
|
// gst_element_set_manager (element, manager);
|
||||||
|
|
||||||
// we do recursion and such for Bins
|
// we do recursion and such for Bins
|
||||||
if (GST_IS_BIN (element)) {
|
if (GST_IS_BIN (element)) {
|
||||||
|
@ -713,6 +818,7 @@ gst_bin_create_plan_func (GstBin *bin)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// clear previous plan state
|
// clear previous plan state
|
||||||
g_list_free (bin->managed_elements);
|
g_list_free (bin->managed_elements);
|
||||||
bin->managed_elements = NULL;
|
bin->managed_elements = NULL;
|
||||||
|
@ -760,12 +866,13 @@ gst_bin_create_plan_func (GstBin *bin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (pending);
|
} while (pending);
|
||||||
|
*/
|
||||||
|
|
||||||
GST_DEBUG (0,"have %d elements to manage, implementing plan\n",bin->num_managed_elements);
|
GST_DEBUG (0,"have %d elements to manage, implementing plan\n",bin->num_managed_elements);
|
||||||
|
|
||||||
gst_bin_schedule(bin);
|
gst_bin_schedule(bin);
|
||||||
|
|
||||||
g_print ("gstbin \"%s\", eos providers:%d\n",
|
GST_DEBUG (0, "gstbin \"%s\", eos providers:%d\n",
|
||||||
GST_ELEMENT_NAME (bin),
|
GST_ELEMENT_NAME (bin),
|
||||||
bin->num_eos_providers);
|
bin->num_eos_providers);
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,10 @@ GtkType gst_bin_get_type (void);
|
||||||
GstElement* gst_bin_new (const gchar *name);
|
GstElement* gst_bin_new (const gchar *name);
|
||||||
#define gst_bin_destroy(bin) gst_object_destroy(GST_OBJECT(bin))
|
#define gst_bin_destroy(bin) gst_object_destroy(GST_OBJECT(bin))
|
||||||
|
|
||||||
|
void gst_bin_set_element_manager (GstElement *element, GstElement *manager);
|
||||||
|
void gst_bin_add_managed_element (GstBin *bin, GstElement *element);
|
||||||
|
void gst_bin_remove_managed_element (GstBin *bin, GstElement *element);
|
||||||
|
|
||||||
/* add and remove elements from the bin */
|
/* add and remove elements from the bin */
|
||||||
void gst_bin_add (GstBin *bin,
|
void gst_bin_add (GstBin *bin,
|
||||||
GstElement *element);
|
GstElement *element);
|
||||||
|
|
|
@ -236,9 +236,15 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
|
||||||
g_return_if_fail (pad != NULL);
|
g_return_if_fail (pad != NULL);
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
g_return_if_fail (GST_IS_PAD (pad));
|
||||||
|
|
||||||
|
// first check to make sure the pad's parent is already set
|
||||||
|
g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
|
||||||
|
|
||||||
|
// then check to see if there's already a pad by that name here
|
||||||
|
g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
|
||||||
|
|
||||||
/* set the pad's parent */
|
/* set the pad's parent */
|
||||||
GST_DEBUG (0,"setting parent of pad '%s'(%p) to '%s'(%p)\n",
|
GST_DEBUG (0,"setting parent of pad '%s' to '%s'\n",
|
||||||
GST_PAD_NAME (pad), pad, GST_ELEMENT_NAME (element), element);
|
GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
|
||||||
gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
|
gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
|
||||||
|
|
||||||
/* add it to the list */
|
/* add it to the list */
|
||||||
|
@ -272,6 +278,9 @@ gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name)
|
||||||
g_return_if_fail (pad != NULL);
|
g_return_if_fail (pad != NULL);
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
g_return_if_fail (GST_IS_PAD (pad));
|
||||||
|
|
||||||
|
// 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(0,"creating new ghost pad called %s, from pad %s:%s\n",name,GST_DEBUG_PAD_NAME(pad));
|
GST_DEBUG(0,"creating new ghost pad called %s, from pad %s:%s\n",name,GST_DEBUG_PAD_NAME(pad));
|
||||||
ghostpad = gst_ghost_pad_new (name, pad);
|
ghostpad = gst_ghost_pad_new (name, pad);
|
||||||
|
|
||||||
|
@ -337,7 +346,7 @@ gst_element_get_pad (GstElement *element, const gchar *name)
|
||||||
walk = element->pads;
|
walk = element->pads;
|
||||||
while (walk) {
|
while (walk) {
|
||||||
GstPad *pad = GST_PAD(walk->data);
|
GstPad *pad = GST_PAD(walk->data);
|
||||||
if (!strcmp (gst_object_get_name (GST_OBJECT(pad)), name)) {
|
if (!strcmp (GST_PAD_NAME(pad), name)) {
|
||||||
GST_DEBUG(GST_CAT_ELEMENT_PADS,"found pad '%s'\n",name);
|
GST_DEBUG(GST_CAT_ELEMENT_PADS,"found pad '%s'\n",name);
|
||||||
return pad;
|
return pad;
|
||||||
}
|
}
|
||||||
|
@ -658,7 +667,7 @@ gst_element_disconnect (GstElement *src, const gchar *srcpadname,
|
||||||
void
|
void
|
||||||
gst_element_error (GstElement *element, const gchar *error)
|
gst_element_error (GstElement *element, const gchar *error)
|
||||||
{
|
{
|
||||||
g_error("GstElement: error in element '%s': %s\n", gst_object_get_name (GST_OBJECT (element)), error);
|
g_error("GstElement: error in element '%s': %s\n", GST_ELEMENT_NAME(element), error);
|
||||||
|
|
||||||
/* FIXME: this is not finished!!! */
|
/* FIXME: this is not finished!!! */
|
||||||
|
|
||||||
|
@ -829,7 +838,7 @@ gst_element_save_thyself (GstObject *object,
|
||||||
|
|
||||||
oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
|
oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
|
||||||
|
|
||||||
xmlNewChild(parent, NULL, "name", gst_object_get_name (GST_OBJECT (element)));
|
xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
|
||||||
|
|
||||||
if (oclass->elementfactory != NULL) {
|
if (oclass->elementfactory != NULL) {
|
||||||
GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
|
GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
|
||||||
|
@ -838,6 +847,9 @@ gst_element_save_thyself (GstObject *object,
|
||||||
xmlNewChild (parent, NULL, "version", factory->details->version);
|
xmlNewChild (parent, NULL, "version", factory->details->version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (element->manager)
|
||||||
|
xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager));
|
||||||
|
|
||||||
// output all args to the element
|
// output all args to the element
|
||||||
type = GTK_OBJECT_TYPE (element);
|
type = GTK_OBJECT_TYPE (element);
|
||||||
while (type != GTK_TYPE_INVALID) {
|
while (type != GTK_TYPE_INVALID) {
|
||||||
|
@ -1081,6 +1093,8 @@ void
|
||||||
gst_element_set_manager (GstElement *element,
|
gst_element_set_manager (GstElement *element,
|
||||||
GstElement *manager)
|
GstElement *manager)
|
||||||
{
|
{
|
||||||
|
if (manager)
|
||||||
|
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting manager to \"%s\"",GST_ELEMENT_NAME(manager));
|
||||||
element->manager = manager;
|
element->manager = manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,11 +58,11 @@ typedef enum {
|
||||||
|
|
||||||
static inline char *_gst_print_statename(int state) {
|
static inline char *_gst_print_statename(int state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case GST_STATE_NONE_PENDING: return "none pending";break;
|
case GST_STATE_NONE_PENDING: return "NONE PENDING";break;
|
||||||
case GST_STATE_NULL: return "null";break;
|
case GST_STATE_NULL: return "NULL";break;
|
||||||
case GST_STATE_READY: return "ready";break;
|
case GST_STATE_READY: return "READY";break;
|
||||||
case GST_STATE_PLAYING: return "playing";break;
|
case GST_STATE_PLAYING: return "PLAYING";break;
|
||||||
case GST_STATE_PAUSED: return "paused";break;
|
case GST_STATE_PAUSED: return "PAUSED";break;
|
||||||
default: return "";
|
default: return "";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
@ -122,6 +122,7 @@ typedef enum {
|
||||||
|
|
||||||
#define GST_ELEMENT_NAME(obj) (GST_OBJECT_NAME(obj))
|
#define GST_ELEMENT_NAME(obj) (GST_OBJECT_NAME(obj))
|
||||||
#define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj))
|
#define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj))
|
||||||
|
#define GST_ELEMENT_MANAGER(obj) (((GstElement*)(obj))->manager)
|
||||||
|
|
||||||
typedef struct _GstElement GstElement;
|
typedef struct _GstElement GstElement;
|
||||||
typedef struct _GstElementClass GstElementClass;
|
typedef struct _GstElementClass GstElementClass;
|
||||||
|
|
|
@ -336,6 +336,33 @@ gst_object_sink (GstObject *object)
|
||||||
}
|
}
|
||||||
#endif /* gst_object_sink */
|
#endif /* gst_object_sink */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_object_check_uniqueness:
|
||||||
|
* @list: a list of #GstObject to check through
|
||||||
|
* @name: the name to search for
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_object_check_uniqueness (GList *list, const gchar *name)
|
||||||
|
{
|
||||||
|
GstObject *child;
|
||||||
|
|
||||||
|
while (list) {
|
||||||
|
child = GST_OBJECT (list->data);
|
||||||
|
list = g_list_next(list);
|
||||||
|
|
||||||
|
if (strcmp(GST_OBJECT_NAME(child), name) == 0) return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
xmlNodePtr
|
xmlNodePtr
|
||||||
gst_object_save_thyself (GstObject *object, xmlNodePtr parent)
|
gst_object_save_thyself (GstObject *object, xmlNodePtr parent)
|
||||||
{
|
{
|
||||||
|
|
|
@ -122,6 +122,8 @@ void gst_object_set_parent (GstObject *object,GstObject *parent);
|
||||||
GstObject* gst_object_get_parent (GstObject *object);
|
GstObject* gst_object_get_parent (GstObject *object);
|
||||||
void gst_object_unparent (GstObject *object);
|
void gst_object_unparent (GstObject *object);
|
||||||
|
|
||||||
|
gboolean gst_object_check_uniqueness (GList *list, const gchar *name);
|
||||||
|
|
||||||
xmlNodePtr gst_object_save_thyself (GstObject *object, xmlNodePtr parent);
|
xmlNodePtr gst_object_save_thyself (GstObject *object, xmlNodePtr parent);
|
||||||
|
|
||||||
/* refcounting */
|
/* refcounting */
|
||||||
|
|
|
@ -331,8 +331,7 @@ void gst_pad_set_chain_function (GstPad *pad,
|
||||||
g_return_if_fail (GST_IS_REAL_PAD (pad));
|
g_return_if_fail (GST_IS_REAL_PAD (pad));
|
||||||
|
|
||||||
GST_RPAD_CHAINFUNC(pad) = chain;
|
GST_RPAD_CHAINFUNC(pad) = chain;
|
||||||
GST_DEBUG (0,"chainfunc for %s:%s(@%p) at %p is set to %p\n",
|
GST_DEBUG (0,"chainfunc for %s:%s is set to %p\n",GST_DEBUG_PAD_NAME(pad),chain);
|
||||||
GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_CHAINFUNC(pad),chain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -104,6 +104,8 @@ gst_pipeline_init (GstPipeline *pipeline)
|
||||||
|
|
||||||
pipeline->src = NULL;
|
pipeline->src = NULL;
|
||||||
pipeline->sinks = NULL;
|
pipeline->sinks = NULL;
|
||||||
|
|
||||||
|
gst_element_set_manager(GST_ELEMENT(pipeline),GST_ELEMENT(pipeline));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -578,7 +578,7 @@ gst_props_load_thyself_func (xmlNodePtr field)
|
||||||
prop = xmlGetProp (field, "min");
|
prop = xmlGetProp (field, "min");
|
||||||
sscanf (prop, "%d", &entry->data.int_range_data.min);
|
sscanf (prop, "%d", &entry->data.int_range_data.min);
|
||||||
g_free (prop);
|
g_free (prop);
|
||||||
prop = xmlGetProp (field, "max");
|
prop = xmlGetProp (field, "min");
|
||||||
sscanf (prop, "%d", &entry->data.int_range_data.max);
|
sscanf (prop, "%d", &entry->data.int_range_data.max);
|
||||||
g_free (prop);
|
g_free (prop);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
//#define DEBUG_ENABLED
|
//#define DEBUG_ENABLED
|
||||||
//#define STATUS_ENABLED
|
//#define STATUS_ENABLED
|
||||||
#ifdef STATUS_ENABLED
|
#ifdef STATUS_ENABLED
|
||||||
#define STATUS(A) GST_DEBUG(0,A, gst_element_get_name(GST_ELEMENT(queue)))
|
#define STATUS(A) GST_DEBUG(0,A, GST_ELEMENT_NAME(queue))
|
||||||
#else
|
#else
|
||||||
#define STATUS(A)
|
#define STATUS(A)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -105,7 +105,6 @@ gst_bin_src_wrapper (int argc,char *argv[])
|
||||||
// fprintf(stderr,"error, no getregionfunc in \"%s\"\n", name);
|
// fprintf(stderr,"error, no getregionfunc in \"%s\"\n", name);
|
||||||
// else
|
// else
|
||||||
buf = (GST_RPAD_GETREGIONFUNC(realpad))((GstPad*)realpad,realpad->regiontype,realpad->offset,realpad->len);
|
buf = (GST_RPAD_GETREGIONFUNC(realpad))((GstPad*)realpad,realpad->regiontype,realpad->offset,realpad->len);
|
||||||
realpad->regiontype = GST_REGION_NONE;
|
|
||||||
} else {
|
} else {
|
||||||
g_return_val_if_fail (GST_RPAD_GETFUNC(realpad) != NULL, 0);
|
g_return_val_if_fail (GST_RPAD_GETFUNC(realpad) != NULL, 0);
|
||||||
// if (GST_RPAD_GETFUNC(realpad) == NULL)
|
// if (GST_RPAD_GETFUNC(realpad) == NULL)
|
||||||
|
@ -363,7 +362,7 @@ void gst_bin_schedule_func(GstBin *bin) {
|
||||||
gst_bin_schedule_cleanup(bin);
|
gst_bin_schedule_cleanup(bin);
|
||||||
|
|
||||||
// next we have to find all the separate scheduling chains
|
// next we have to find all the separate scheduling chains
|
||||||
GST_DEBUG (0,"\nattempting to find scheduling chains...\n");
|
GST_DEBUG (0,"attempting to find scheduling chains...\n");
|
||||||
// first make a copy of the managed_elements we can mess with
|
// first make a copy of the managed_elements we can mess with
|
||||||
elements = g_list_copy (bin->managed_elements);
|
elements = g_list_copy (bin->managed_elements);
|
||||||
// we have to repeat until the list is empty to get all chains
|
// we have to repeat until the list is empty to get all chains
|
||||||
|
@ -428,6 +427,7 @@ void gst_bin_schedule_func(GstBin *bin) {
|
||||||
if (!GST_IS_REAL_PAD(pad)) continue;
|
if (!GST_IS_REAL_PAD(pad)) continue;
|
||||||
GST_DEBUG (0,"have pad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
|
GST_DEBUG (0,"have pad %s:%s\n",GST_DEBUG_PAD_NAME(pad));
|
||||||
|
|
||||||
|
if (GST_RPAD_PEER(pad) == NULL) continue;
|
||||||
if (GST_RPAD_PEER(pad) == NULL) GST_ERROR(pad,"peer is null!");
|
if (GST_RPAD_PEER(pad) == NULL) GST_ERROR(pad,"peer is null!");
|
||||||
g_assert(GST_RPAD_PEER(pad) != NULL);
|
g_assert(GST_RPAD_PEER(pad) != NULL);
|
||||||
g_assert(GST_PAD_PARENT (GST_PAD(GST_RPAD_PEER(pad))) != NULL);
|
g_assert(GST_PAD_PARENT (GST_PAD(GST_RPAD_PEER(pad))) != NULL);
|
||||||
|
@ -744,3 +744,147 @@ void gst_bin_schedule_func(GstBin *bin) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*************** INCREMENTAL SCHEDULING CODE STARTS HERE ***************/
|
||||||
|
|
||||||
|
static GstSchedule realsched;
|
||||||
|
static GstSchedule *sched = &realsched;
|
||||||
|
|
||||||
|
|
||||||
|
/* this function will look at a pad and determine if the peer parent is
|
||||||
|
* a possible candidate for connecting up in the same chain. */
|
||||||
|
GstElement *gst_schedule_check_pad (GstSchedule *schedule, GstPad *pad) {
|
||||||
|
GstPad *peer;
|
||||||
|
GstElement *peerelement;
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_SCHEDULING, "checking pad %s:%s for peer in scheduler",
|
||||||
|
GST_DEBUG_PAD_NAME(pad));
|
||||||
|
|
||||||
|
peer = GST_PAD(GST_PAD_PEER (pad));
|
||||||
|
if (peer == NULL) return NULL;
|
||||||
|
peerelement = GST_ELEMENT(GST_PAD_PARENT (peer));
|
||||||
|
|
||||||
|
// first of all, if the peer element is decoupled, it will be in the same chain
|
||||||
|
if (GST_FLAG_IS_SET(peerelement,GST_ELEMENT_DECOUPLED))
|
||||||
|
return peerelement;
|
||||||
|
|
||||||
|
// now check to see if it's in the same schedule
|
||||||
|
if (g_list_find(sched->elements,peerelement))
|
||||||
|
return peerelement;
|
||||||
|
|
||||||
|
// otherwise it's not a candidate
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstScheduleChain *
|
||||||
|
gst_schedule_chain_new (GstSchedule *sched)
|
||||||
|
{
|
||||||
|
GstScheduleChain *chain = g_new (GstScheduleChain, 1);
|
||||||
|
|
||||||
|
chain->parent = sched;
|
||||||
|
chain->elements = NULL;
|
||||||
|
chain->num_elements = 0;
|
||||||
|
chain->entry = NULL;
|
||||||
|
chain->need_cothreads = TRUE;
|
||||||
|
chain->schedule = FALSE;
|
||||||
|
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_schedule_chain_elements (GstSchedule *schedule, GstElement *element1, GstElement *element2)
|
||||||
|
{
|
||||||
|
GList *chains;
|
||||||
|
GstScheduleChain *chain;
|
||||||
|
GstScheduleChain *chain1 = NULL, *chain2 = NULL;
|
||||||
|
GstElement *element;
|
||||||
|
|
||||||
|
// first find the chains that hold the two
|
||||||
|
chains = sched->chains;
|
||||||
|
while (chains) {
|
||||||
|
chain = (GstScheduleChain *)(chains->data);
|
||||||
|
chains = g_list_next(chains);
|
||||||
|
|
||||||
|
if (g_list_find (chain->elements,element1))
|
||||||
|
chain1 = chain;
|
||||||
|
if (g_list_find (chain->elements,element2))
|
||||||
|
chain2 = chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now, if neither element has a chain, create one
|
||||||
|
if ((chain1 == NULL) && (chain2 == NULL)) {
|
||||||
|
GST_INFO (GST_CAT_SCHEDULING, "creating new chain to hold two new elements");
|
||||||
|
chain = gst_schedule_chain_new (sched);
|
||||||
|
chain->elements = g_list_prepend (chain->elements, element1);
|
||||||
|
chain->elements = g_list_prepend (chain->elements, element2);
|
||||||
|
chain->num_elements = 2;
|
||||||
|
|
||||||
|
sched->chains = g_list_prepend (sched->chains, chain);
|
||||||
|
sched->num_chains++;
|
||||||
|
|
||||||
|
// otherwise if both have chains already, join them
|
||||||
|
} else if ((chain1 != NULL) && (chain2 != NULL)) {
|
||||||
|
GST_INFO (GST_CAT_SCHEDULING, "joining two existing chains together");
|
||||||
|
// take the contents of chain2 and merge them into chain1
|
||||||
|
chain1->elements = g_list_concat (chain1->elements, chain2->elements);
|
||||||
|
chain1->num_elements += chain2->num_elements;
|
||||||
|
|
||||||
|
g_free(chain2);
|
||||||
|
|
||||||
|
// otherwise one has a chain already, the other doesn't
|
||||||
|
} else {
|
||||||
|
// pick out which one has the chain, and which doesn't
|
||||||
|
if (chain1 != NULL) chain = chain1, element = element2;
|
||||||
|
else chain = chain2, element = element1;
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_SCHEDULING, "adding element to existing chain");
|
||||||
|
chain->elements = g_list_prepend (chain->elements, element);
|
||||||
|
chain->num_elements++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_schedule_add_element (GstSchedule *schedule, GstElement *element)
|
||||||
|
{
|
||||||
|
GList *pads;
|
||||||
|
GstPad *pad;
|
||||||
|
GstElement *peerelement;
|
||||||
|
|
||||||
|
g_return_if_fail (element != NULL);
|
||||||
|
g_return_if_fail (GST_IS_ELEMENT(element));
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_SCHEDULING, "adding element \"%s\" to schedule",
|
||||||
|
GST_ELEMENT_NAME(element));
|
||||||
|
|
||||||
|
// first add it to the list of elements that are to be scheduled
|
||||||
|
sched->elements = g_list_prepend (sched->elements, element);
|
||||||
|
sched->num_elements++;
|
||||||
|
|
||||||
|
// now look through the pads and see what we need to do
|
||||||
|
pads = element->pads;
|
||||||
|
while (pads) {
|
||||||
|
pad = GST_PAD(pads->data);
|
||||||
|
pads = g_list_next(pads);
|
||||||
|
|
||||||
|
// if the peer element is a candidate
|
||||||
|
if ((peerelement = gst_schedule_check_pad(sched,pad))) {
|
||||||
|
GST_INFO (GST_CAT_SCHEDULING, "peer is in same schedule, chaining together");
|
||||||
|
// make sure that the two elements are in the same chain
|
||||||
|
gst_schedule_chain_elements (sched,element,peerelement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_schedule_remove_element (GstSchedule *schedule, GstElement *element)
|
||||||
|
{
|
||||||
|
g_return_if_fail (element != NULL);
|
||||||
|
g_return_if_fail (GST_IS_ELEMENT(element));
|
||||||
|
|
||||||
|
if (g_list_find (sched->elements, element)) {
|
||||||
|
GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from schedule",
|
||||||
|
GST_ELEMENT_NAME(element));
|
||||||
|
sched->elements = g_list_remove (sched->elements, element);
|
||||||
|
sched->num_elements--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#ifndef __GST_SCHEDULER_H__
|
#ifndef __GST_SCHEDULER_H__
|
||||||
#define __GST_SCHEDULER_H__
|
#define __GST_SCHEDULER_H__
|
||||||
|
|
||||||
|
#include <gst/gstelement.h>
|
||||||
|
/// ACK!
|
||||||
#include <gst/gstbin.h>
|
#include <gst/gstbin.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,8 +34,37 @@ extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _GstScheduleChain GstScheduleChain;
|
||||||
|
typedef struct _GstSchedule GstSchedule;
|
||||||
|
|
||||||
|
struct _GstSchedule {
|
||||||
|
GstElement *parent;
|
||||||
|
|
||||||
|
GList *elements;
|
||||||
|
gint num_elements;
|
||||||
|
|
||||||
|
GList *chains;
|
||||||
|
gint num_chains;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstScheduleChain {
|
||||||
|
GstSchedule *parent;
|
||||||
|
|
||||||
|
GList *elements;
|
||||||
|
gint num_elements;
|
||||||
|
|
||||||
|
GstElement *entry;
|
||||||
|
|
||||||
|
gboolean need_cothreads;
|
||||||
|
gboolean schedule;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
void gst_bin_schedule_func(GstBin *bin);
|
void gst_bin_schedule_func(GstBin *bin);
|
||||||
|
|
||||||
|
void gst_schedule_add_element(GstSchedule *schedule,GstElement *element);
|
||||||
|
void gst_schedule_remove_element(GstSchedule *schedule,GstElement *element);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ gst_thread_class_init (GstThreadClass *klass)
|
||||||
|
|
||||||
gstelement_class->change_state = gst_thread_change_state;
|
gstelement_class->change_state = gst_thread_change_state;
|
||||||
|
|
||||||
gstbin_class->schedule = gst_thread_schedule_dummy;
|
// gstbin_class->schedule = gst_thread_schedule_dummy;
|
||||||
|
|
||||||
gtkobject_class->set_arg = gst_thread_set_arg;
|
gtkobject_class->set_arg = gst_thread_set_arg;
|
||||||
gtkobject_class->get_arg = gst_thread_get_arg;
|
gtkobject_class->get_arg = gst_thread_get_arg;
|
||||||
|
@ -134,6 +134,8 @@ gst_thread_init (GstThread *thread)
|
||||||
|
|
||||||
thread->lock = g_mutex_new();
|
thread->lock = g_mutex_new();
|
||||||
thread->cond = g_cond_new();
|
thread->cond = g_cond_new();
|
||||||
|
|
||||||
|
gst_element_set_manager(GST_ELEMENT(thread),GST_ELEMENT(thread));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -142,7 +144,7 @@ gst_thread_schedule_dummy (GstBin *bin)
|
||||||
g_return_if_fail (GST_IS_THREAD (bin));
|
g_return_if_fail (GST_IS_THREAD (bin));
|
||||||
|
|
||||||
if (!GST_FLAG_IS_SET (GST_THREAD (bin), GST_THREAD_STATE_SPINNING))
|
if (!GST_FLAG_IS_SET (GST_THREAD (bin), GST_THREAD_STATE_SPINNING))
|
||||||
GST_INFO (GST_CAT_THREAD,"gstthread: scheduling delayed until thread starts");
|
GST_INFO (GST_CAT_THREAD,"scheduling delayed until thread starts");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -156,13 +158,13 @@ gst_thread_set_arg (GtkObject *object,
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case ARG_CREATE_THREAD:
|
case ARG_CREATE_THREAD:
|
||||||
if (GTK_VALUE_BOOL (*arg)) {
|
if (GTK_VALUE_BOOL (*arg)) {
|
||||||
GST_INFO (GST_CAT_THREAD,"gstthread: turning ON the creation of the thread");
|
GST_INFO (GST_CAT_THREAD,"turning ON the creation of the thread");
|
||||||
GST_FLAG_SET (object, GST_THREAD_CREATE);
|
GST_FLAG_SET (object, GST_THREAD_CREATE);
|
||||||
GST_DEBUG (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
|
// GST_DEBUG (0,"flags are 0x%08x\n", GST_FLAGS (object));
|
||||||
} else {
|
} else {
|
||||||
GST_INFO (GST_CAT_THREAD,"gstthread: turning OFF the creation of the thread");
|
GST_INFO (GST_CAT_THREAD,"gstthread: turning OFF the creation of the thread");
|
||||||
GST_FLAG_UNSET (object, GST_THREAD_CREATE);
|
GST_FLAG_UNSET (object, GST_THREAD_CREATE);
|
||||||
GST_DEBUG (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
|
// GST_DEBUG (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -209,75 +211,68 @@ gst_thread_change_state (GstElement *element)
|
||||||
{
|
{
|
||||||
GstThread *thread;
|
GstThread *thread;
|
||||||
gboolean stateset = GST_STATE_SUCCESS;
|
gboolean stateset = GST_STATE_SUCCESS;
|
||||||
gint pending, transition;
|
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_THREAD(element), FALSE);
|
g_return_val_if_fail (GST_IS_THREAD(element), FALSE);
|
||||||
GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME(element));
|
GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME(element));
|
||||||
|
|
||||||
thread = GST_THREAD (element);
|
thread = GST_THREAD (element);
|
||||||
|
|
||||||
GST_INFO (GST_CAT_THREAD,"gstthread: thread \"%s\" change state %d",
|
thread->transition = GST_STATE_TRANSITION(element);
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_THREAD,"thread \"%s\" changing state to %s",
|
||||||
GST_ELEMENT_NAME (GST_ELEMENT (element)),
|
GST_ELEMENT_NAME (GST_ELEMENT (element)),
|
||||||
GST_STATE_PENDING (element));
|
_gst_print_statename(GST_STATE_PENDING (element)));
|
||||||
|
|
||||||
pending = GST_STATE_PENDING (element);
|
|
||||||
transition = GST_STATE_TRANSITION (element);
|
|
||||||
|
|
||||||
// if (pending == GST_STATE (element)) return GST_STATE_SUCCESS;
|
|
||||||
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
switch (thread->transition) {
|
||||||
stateset = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
|
||||||
|
|
||||||
GST_INFO (GST_CAT_THREAD, "gstthread: stateset %d %d %d %02x", GST_STATE (element), stateset,
|
|
||||||
GST_STATE_PENDING (element), GST_STATE_TRANSITION (element));
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_NULL_TO_READY:
|
case GST_STATE_NULL_TO_READY:
|
||||||
// if (!stateset) return FALSE;
|
|
||||||
// we want to prepare our internal state for doing the iterations
|
// we want to prepare our internal state for doing the iterations
|
||||||
GST_INFO (GST_CAT_THREAD, "gstthread: preparing thread \"%s\" for iterations:",
|
GST_INFO (GST_CAT_THREAD, "preparing thread \"%s\" for iterations:",
|
||||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||||
|
|
||||||
// set the state to idle
|
// set the state to idle
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||||
// create the thread if that's what we're supposed to do
|
// 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_INFO (GST_CAT_THREAD, "flags are 0x%08x", GST_FLAGS (thread));
|
||||||
|
|
||||||
if (GST_FLAG_IS_SET (thread, GST_THREAD_CREATE)) {
|
if (GST_FLAG_IS_SET (thread, GST_THREAD_CREATE)) {
|
||||||
GST_INFO (GST_CAT_THREAD, "gstthread: starting thread \"%s\"",
|
GST_DEBUG (GST_CAT_THREAD, "starting thread \"%s\"\n",
|
||||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||||
|
|
||||||
// create the thread
|
// create the thread
|
||||||
pthread_create (&thread->thread_id, NULL,
|
pthread_create (&thread->thread_id, NULL,
|
||||||
gst_thread_main_loop, thread);
|
gst_thread_main_loop, thread);
|
||||||
|
|
||||||
// wait for it to 'spin up'
|
// wait for it to 'spin up'
|
||||||
// gst_thread_wait_thread (thread);
|
gst_thread_wait_thread (thread);
|
||||||
} else {
|
} else {
|
||||||
GST_INFO (GST_CAT_THREAD, "gstthread: NOT starting thread \"%s\"",
|
GST_INFO (GST_CAT_THREAD, "NOT starting thread \"%s\"",
|
||||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||||
|
|
||||||
|
// punt and change state on all the children
|
||||||
|
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||||
|
stateset = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
case GST_STATE_READY_TO_PLAYING:
|
case GST_STATE_READY_TO_PLAYING:
|
||||||
if (!stateset) return FALSE;
|
if (!stateset) return FALSE;
|
||||||
GST_INFO (GST_CAT_THREAD, "gstthread: starting thread \"%s\"",
|
GST_INFO (GST_CAT_THREAD, "starting thread \"%s\"",
|
||||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||||
|
|
||||||
GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
|
GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
|
||||||
gst_thread_signal_thread (thread);
|
gst_thread_signal_thread (thread);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PLAYING_TO_PAUSED:
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
GST_INFO (GST_CAT_THREAD,"gstthread: pausing thread \"%s\"",
|
GST_INFO (GST_CAT_THREAD,"pausing thread \"%s\"",
|
||||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||||
|
|
||||||
//GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
|
//GST_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
|
||||||
gst_thread_signal_thread (thread);
|
gst_thread_signal_thread (thread);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_NULL:
|
case GST_STATE_READY_TO_NULL:
|
||||||
GST_INFO (GST_CAT_THREAD,"gstthread: stopping thread \"%s\"",
|
GST_INFO (GST_CAT_THREAD,"stopping thread \"%s\"",
|
||||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||||
|
|
||||||
GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
|
GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
|
||||||
|
@ -301,16 +296,25 @@ static void *
|
||||||
gst_thread_main_loop (void *arg)
|
gst_thread_main_loop (void *arg)
|
||||||
{
|
{
|
||||||
GstThread *thread = GST_THREAD (arg);
|
GstThread *thread = GST_THREAD (arg);
|
||||||
|
gint stateset;
|
||||||
|
|
||||||
GST_INFO (GST_CAT_THREAD,"gstthread: thread \"%s\" is running with PID %d",
|
GST_INFO (GST_CAT_THREAD,"thread \"%s\" is running with PID %d",
|
||||||
GST_ELEMENT_NAME (GST_ELEMENT (thread)), getpid ());
|
GST_ELEMENT_NAME (GST_ELEMENT (thread)), getpid ());
|
||||||
|
|
||||||
|
// first we need to change the state of all the children
|
||||||
|
GST_DEBUG (GST_CAT_THREAD,"thread started, setting children's state\n");
|
||||||
|
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||||
|
stateset = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT(thread));
|
||||||
|
|
||||||
// construct the plan and signal back
|
// construct the plan and signal back
|
||||||
|
GST_DEBUG (GST_CAT_THREAD,"creating plan for thread\n");
|
||||||
if (GST_BIN_CLASS (parent_class)->schedule)
|
if (GST_BIN_CLASS (parent_class)->schedule)
|
||||||
GST_BIN_CLASS (parent_class)->schedule (GST_BIN (thread));
|
GST_BIN_CLASS (parent_class)->schedule (GST_BIN (thread));
|
||||||
|
|
||||||
gst_thread_signal_thread (thread);
|
gst_thread_signal_thread (thread);
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_THREAD,"thread has signalled to parent at startup");
|
||||||
|
|
||||||
while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) {
|
while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) {
|
||||||
if (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
|
if (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
|
||||||
if (!gst_bin_iterate (GST_BIN (thread))) {
|
if (!gst_bin_iterate (GST_BIN (thread))) {
|
||||||
|
|
|
@ -66,6 +66,8 @@ struct _GstThread {
|
||||||
pthread_t thread_id; /* id of the thread, if any */
|
pthread_t thread_id; /* id of the thread, if any */
|
||||||
GMutex *lock; /* thread lock/condititon pair... */
|
GMutex *lock; /* thread lock/condititon pair... */
|
||||||
GCond *cond; /* used to control the thread */
|
GCond *cond; /* used to control the thread */
|
||||||
|
|
||||||
|
gint transition; /* the current state transition */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstThreadClass {
|
struct _GstThreadClass {
|
||||||
|
|
|
@ -412,8 +412,6 @@ gst_media_play_frame_displayed (GstPlay *play,
|
||||||
size = gst_play_get_media_size (play);
|
size = gst_play_get_media_size (play);
|
||||||
current_offset = gst_play_get_media_offset (play);
|
current_offset = gst_play_get_media_offset (play);
|
||||||
|
|
||||||
//g_print ("%lu %lu %lu %lu\n", current_time, total_time, size, current_offset);
|
|
||||||
|
|
||||||
if (current_time != mplay->last_time) {
|
if (current_time != mplay->last_time) {
|
||||||
gdk_threads_enter ();
|
gdk_threads_enter ();
|
||||||
gst_media_play_update_status_area (mplay, current_time, total_time);
|
gst_media_play_update_status_area (mplay, current_time, total_time);
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
//#define DEBUG_ENABLED
|
//#define DEBUG_ENABLED
|
||||||
//#define STATUS_ENABLED
|
//#define STATUS_ENABLED
|
||||||
#ifdef STATUS_ENABLED
|
#ifdef STATUS_ENABLED
|
||||||
#define STATUS(A) GST_DEBUG(0,A, gst_element_get_name(GST_ELEMENT(queue)))
|
#define STATUS(A) GST_DEBUG(0,A, GST_ELEMENT_NAME(queue))
|
||||||
#else
|
#else
|
||||||
#define STATUS(A)
|
#define STATUS(A)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
SUBDIRS = sched eos
|
SUBDIRS = sched eos
|
||||||
|
|
||||||
noinst_PROGRAMS = init loadall simplefake states caps queue registry \
|
noinst_PROGRAMS = init loadall simplefake states caps queue registry \
|
||||||
paranoia rip mp3encode autoplug props case4 markup load tee
|
paranoia rip mp3encode autoplug props case4 markup load tee incsched
|
||||||
|
|
||||||
# we have nothing but apps here, we can do this safely
|
# we have nothing but apps here, we can do this safely
|
||||||
LIBS += $(GST_LIBS)
|
LIBS += $(GST_LIBS)
|
||||||
|
|
50
tests/incsched.c
Normal file
50
tests/incsched.c
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
int main(int argc,char *argv[]) {
|
||||||
|
GstBin *thread, *bin;
|
||||||
|
GstElement *src, *identity, *sink;
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
g_print("\n\nConnecting:\n");
|
||||||
|
gst_element_connect(src,"src",identity,"sink");
|
||||||
|
gst_element_connect(identity,"src",sink,"sink");
|
||||||
|
|
||||||
|
g_print("\n\nAssembling things:\n");
|
||||||
|
g_print("\nAdding src to thread:\n");
|
||||||
|
gst_bin_add(thread,src);
|
||||||
|
g_print("there are %d managed elements in thread\n",thread->num_managed_elements);
|
||||||
|
|
||||||
|
g_print("\nAdding identity to thread:\n");
|
||||||
|
gst_bin_add(thread,identity);
|
||||||
|
g_print("there are %d managed elements in thread\n",thread->num_managed_elements);
|
||||||
|
|
||||||
|
g_print("\nAdding sink to thread:\n");
|
||||||
|
gst_bin_add(thread,sink);
|
||||||
|
g_print("there are %d managed elements in thread\n",thread->num_managed_elements);
|
||||||
|
|
||||||
|
// g_print("\nAdding bin to thread:\n");
|
||||||
|
// gst_bin_add(thread,bin);
|
||||||
|
// g_print("there are %d managed elements in thread now\n",thread->num_managed_elements);
|
||||||
|
// g_print("there are %d managed elements in bin now\n",bin->num_managed_elements);
|
||||||
|
|
||||||
|
/*
|
||||||
|
g_print("\n\nSaving xml:\n");
|
||||||
|
xmlSaveFile("threadsync.gst", gst_xml_write(GST_ELEMENT(thread)));
|
||||||
|
*/
|
||||||
|
|
||||||
|
// g_print("\n\nSetting state to READY:\n");
|
||||||
|
// gst_element_set_state(thread,GST_STATE_READY);
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
}
|
Loading…
Reference in a new issue