mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-12 03:16:33 +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 =
|
||||
endif
|
||||
|
||||
if BUILD_DOCS
|
||||
SUBDIRS_DOCS = docs
|
||||
else
|
||||
SUBDIRS_DOCS =
|
||||
endif
|
||||
|
||||
SUBDIRS = include gst libs plugins tools test tests examples \
|
||||
$(SUBDIRS_LGG) $(SUBDIRS_DOCS)
|
||||
SUBDIRS = include gst libs plugins tools test tests examples $(SUBDIRS_LGG) docs
|
||||
|
||||
# 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
|
||||
|
|
16
configure.in
16
configure.in
|
@ -50,6 +50,9 @@ AM_DISABLE_STATIC
|
|||
AC_LIBTOOL_DLOPEN
|
||||
AM_PROG_LIBTOOL
|
||||
|
||||
dnl ALL_LINGUAS=""
|
||||
dnl AM_GNU_GETTEXT
|
||||
|
||||
CFLAGS=""
|
||||
|
||||
dnl ##############################
|
||||
|
@ -484,16 +487,6 @@ AC_ARG_WITH(win32_libdir,
|
|||
esac],
|
||||
[:]) 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 # 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_LIBXV, test "x$HAVE_LIBXV" = "xyes")
|
||||
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_DB2PS, $HAVE_DB2PS)
|
||||
AM_CONDITIONAL(HAVE_PS2PDF, $HAVE_PS2PDF)
|
||||
|
@ -656,6 +648,8 @@ dnl # Make the output files #
|
|||
dnl #########################
|
||||
|
||||
AC_OUTPUT([Makefile
|
||||
intl/Makefile
|
||||
po/Makefile.in
|
||||
include/Makefile
|
||||
include/wine/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 \
|
||||
$(GSTARCH_SRCS)
|
||||
|
||||
|
||||
##### Oh this sucks so badly. This isn't funny. #####
|
||||
|
||||
# the compiler shoots cothreads.c in the head at -O6
|
||||
# FIXME: these manual rules break the dependency generation, so we have a
|
||||
# nasty hack here.
|
||||
#LTCOMPILE2=$(LTCOMPILE) -O2
|
||||
#COMPILE2=$(COMPILE) -O2
|
||||
|
||||
cothreads.lo: cothreads.c cothreads.h gst_private.h ../config.h gstinfo.c \
|
||||
gstarch.h gsti386.h
|
||||
$(LIBTOOL) --mode=compile $(COMPILE) -O2 -c $<
|
||||
cothreads.o: cothreads.c cothreads.h gst_private.h ../config.h gstinfo.c \
|
||||
gstarch.h gsti386.h
|
||||
$(COMPILE) -O2 -c $<
|
||||
|
||||
# NOTDEPEND.cothreads.lo: cothreads.c
|
||||
# NOTDEPEND $(LTCOMPILE2) -c $<
|
||||
# NOTDEPEND.cothreads.o: cothreads.c
|
||||
# NOTDEPEND $(COMPILE2) -c $<
|
||||
|
||||
#cothreads.lo: cothreads.c
|
||||
# @echo '$(LTCOMPILE2) -c $<'; \
|
||||
# $(LTCOMPILE2) -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
|
||||
#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 #####
|
||||
|
||||
LTCOMPILE2=$(LTCOMPILE) -O2
|
||||
COMPILE2=$(COMPILE) -O2
|
||||
cothreads.lo: cothreads.c
|
||||
@echo '$(LTCOMPILE2) -c $<'; \
|
||||
$(LTCOMPILE2) -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
|
||||
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
|
||||
|
||||
libgstincludedir = $(includedir)/gst
|
||||
libgstinclude_HEADERS = \
|
||||
|
|
|
@ -263,7 +263,7 @@ cothread_switch (cothread_state *thread)
|
|||
if (current == thread) goto selfswitch;
|
||||
|
||||
// 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;
|
||||
|
||||
|
|
125
gst/gstbin.c
125
gst/gstbin.c
|
@ -155,6 +155,85 @@ gst_bin_new (const gchar *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:
|
||||
* @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 (GST_IS_ELEMENT (element));
|
||||
|
||||
GST_DEBUG_ENTER ("");
|
||||
|
||||
// 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) ||
|
||||
(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->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... */
|
||||
// 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) ||
|
||||
(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) {
|
||||
// FIXME this should be a warning!!!
|
||||
GST_ERROR_OBJECT(bin,element,"no such element in bin");
|
||||
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));
|
||||
bin->children = g_list_remove (bin->children, element);
|
||||
bin->numchildren--;
|
||||
|
@ -286,9 +385,13 @@ gst_bin_change_state (GstElement *element)
|
|||
// 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_print_statename (GST_STATE (element)),
|
||||
_gst_print_statename (GST_STATE_PENDING (element)));
|
||||
|
||||
return gst_bin_change_state_norecurse (bin);
|
||||
}
|
||||
|
||||
|
@ -312,7 +415,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);
|
||||
|
@ -411,7 +514,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);
|
||||
|
@ -635,6 +738,7 @@ gst_bin_create_plan_func (GstBin *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)) {
|
||||
|
@ -651,6 +755,7 @@ gst_bin_create_plan_func (GstBin *bin)
|
|||
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
|
||||
|
@ -669,9 +774,9 @@ gst_bin_create_plan_func (GstBin *bin)
|
|||
#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);
|
||||
// // 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)) {
|
||||
|
@ -713,6 +818,7 @@ gst_bin_create_plan_func (GstBin *bin)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
// clear previous plan state
|
||||
g_list_free (bin->managed_elements);
|
||||
bin->managed_elements = NULL;
|
||||
|
@ -760,12 +866,13 @@ gst_bin_create_plan_func (GstBin *bin)
|
|||
}
|
||||
}
|
||||
} 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_DEBUG (0, "gstbin \"%s\", eos providers:%d\n",
|
||||
GST_ELEMENT_NAME (bin),
|
||||
bin->num_eos_providers);
|
||||
|
||||
|
|
|
@ -116,6 +116,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);
|
||||
|
|
|
@ -236,9 +236,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 (0,"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 */
|
||||
|
@ -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 (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));
|
||||
ghostpad = gst_ghost_pad_new (name, pad);
|
||||
|
||||
|
@ -337,7 +346,7 @@ gst_element_get_pad (GstElement *element, const gchar *name)
|
|||
walk = element->pads;
|
||||
while (walk) {
|
||||
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);
|
||||
return pad;
|
||||
}
|
||||
|
@ -658,7 +667,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!!! */
|
||||
|
||||
|
@ -829,7 +838,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;
|
||||
|
@ -838,6 +847,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) {
|
||||
|
@ -1081,6 +1093,8 @@ void
|
|||
gst_element_set_manager (GstElement *element,
|
||||
GstElement *manager)
|
||||
{
|
||||
if (manager)
|
||||
GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting manager to \"%s\"",GST_ELEMENT_NAME(manager));
|
||||
element->manager = manager;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,11 +58,11 @@ typedef enum {
|
|||
|
||||
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;
|
||||
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 "";
|
||||
|
@ -122,6 +122,7 @@ 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)
|
||||
|
||||
typedef struct _GstElement GstElement;
|
||||
typedef struct _GstElementClass GstElementClass;
|
||||
|
|
|
@ -336,6 +336,33 @@ gst_object_sink (GstObject *object)
|
|||
}
|
||||
#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
|
||||
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);
|
||||
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 */
|
||||
|
|
|
@ -331,8 +331,7 @@ 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 (0,"chainfunc for %s:%s is set to %p\n",GST_DEBUG_PAD_NAME(pad),chain);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -104,6 +104,8 @@ gst_pipeline_init (GstPipeline *pipeline)
|
|||
|
||||
pipeline->src = 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");
|
||||
sscanf (prop, "%d", &entry->data.int_range_data.min);
|
||||
g_free (prop);
|
||||
prop = xmlGetProp (field, "max");
|
||||
prop = xmlGetProp (field, "min");
|
||||
sscanf (prop, "%d", &entry->data.int_range_data.max);
|
||||
g_free (prop);
|
||||
}
|
||||
|
|
|
@ -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(0,A, GST_ELEMENT_NAME(queue))
|
||||
#else
|
||||
#define STATUS(A)
|
||||
#endif
|
||||
|
|
|
@ -105,7 +105,6 @@ gst_bin_src_wrapper (int argc,char *argv[])
|
|||
// fprintf(stderr,"error, no getregionfunc in \"%s\"\n", name);
|
||||
// else
|
||||
buf = (GST_RPAD_GETREGIONFUNC(realpad))((GstPad*)realpad,realpad->regiontype,realpad->offset,realpad->len);
|
||||
realpad->regiontype = GST_REGION_NONE;
|
||||
} else {
|
||||
g_return_val_if_fail (GST_RPAD_GETFUNC(realpad) != NULL, 0);
|
||||
// if (GST_RPAD_GETFUNC(realpad) == NULL)
|
||||
|
@ -363,7 +362,7 @@ void gst_bin_schedule_func(GstBin *bin) {
|
|||
gst_bin_schedule_cleanup(bin);
|
||||
|
||||
// next we have to find all the separate scheduling chains
|
||||
GST_DEBUG (0,"\nattempting to find scheduling chains...\n");
|
||||
GST_DEBUG (0,"attempting to find scheduling chains...\n");
|
||||
// first make a copy of the managed_elements we can mess with
|
||||
elements = g_list_copy (bin->managed_elements);
|
||||
// we have to repeat until the list is empty to get all chains
|
||||
|
@ -428,6 +427,7 @@ void gst_bin_schedule_func(GstBin *bin) {
|
|||
if (!GST_IS_REAL_PAD(pad)) continue;
|
||||
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!");
|
||||
g_assert(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__
|
||||
#define __GST_SCHEDULER_H__
|
||||
|
||||
#include <gst/gstelement.h>
|
||||
/// ACK!
|
||||
#include <gst/gstbin.h>
|
||||
|
||||
|
||||
|
@ -32,8 +34,37 @@ extern "C" {
|
|||
#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_schedule_add_element(GstSchedule *schedule,GstElement *element);
|
||||
void gst_schedule_remove_element(GstSchedule *schedule,GstElement *element);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ gst_thread_class_init (GstThreadClass *klass)
|
|||
|
||||
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;
|
||||
|
@ -134,6 +134,8 @@ gst_thread_init (GstThread *thread)
|
|||
|
||||
thread->lock = g_mutex_new();
|
||||
thread->cond = g_cond_new();
|
||||
|
||||
gst_element_set_manager(GST_ELEMENT(thread),GST_ELEMENT(thread));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -142,7 +144,7 @@ gst_thread_schedule_dummy (GstBin *bin)
|
|||
g_return_if_fail (GST_IS_THREAD (bin));
|
||||
|
||||
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
|
||||
|
@ -156,13 +158,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 (0,"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 (0,"gstthread: flags are 0x%08x\n", GST_FLAGS (object));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -209,75 +211,68 @@ gst_thread_change_state (GstElement *element)
|
|||
{
|
||||
GstThread *thread;
|
||||
gboolean stateset = GST_STATE_SUCCESS;
|
||||
gint pending, transition;
|
||||
|
||||
g_return_val_if_fail (GST_IS_THREAD(element), FALSE);
|
||||
GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME(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_STATE_PENDING (element));
|
||||
|
||||
pending = GST_STATE_PENDING (element);
|
||||
transition = GST_STATE_TRANSITION (element);
|
||||
|
||||
// if (pending == GST_STATE (element)) return GST_STATE_SUCCESS;
|
||||
_gst_print_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));
|
||||
|
||||
switch (transition) {
|
||||
switch (thread->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_INFO (GST_CAT_THREAD, "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_INFO (GST_CAT_THREAD, "flags are 0x%08x", GST_FLAGS (thread));
|
||||
|
||||
if (GST_FLAG_IS_SET (thread, GST_THREAD_CREATE)) {
|
||||
GST_INFO (GST_CAT_THREAD, "gstthread: starting thread \"%s\"",
|
||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||
GST_DEBUG (GST_CAT_THREAD, "starting thread \"%s\"\n",
|
||||
GST_ELEMENT_NAME (GST_ELEMENT (element)));
|
||||
|
||||
// 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);
|
||||
gst_thread_wait_thread (thread);
|
||||
} 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)));
|
||||
|
||||
// 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_PAUSED_TO_PLAYING:
|
||||
case GST_STATE_READY_TO_PLAYING:
|
||||
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_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
|
||||
gst_thread_signal_thread (thread);
|
||||
break;
|
||||
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_FLAG_UNSET(thread,GST_THREAD_STATE_SPINNING);
|
||||
gst_thread_signal_thread (thread);
|
||||
break;
|
||||
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_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
|
||||
|
@ -301,16 +296,25 @@ 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_INFO (GST_CAT_THREAD,"thread \"%s\" is running with PID %d",
|
||||
GST_ELEMENT_NAME (GST_ELEMENT (thread)), getpid ());
|
||||
|
||||
// first we need to change the state of all the children
|
||||
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
|
||||
GST_DEBUG (GST_CAT_THREAD,"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);
|
||||
|
||||
GST_INFO (GST_CAT_THREAD,"thread has signalled to parent at startup");
|
||||
|
||||
while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING)) {
|
||||
if (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
|
||||
if (!gst_bin_iterate (GST_BIN (thread))) {
|
||||
|
|
|
@ -66,6 +66,8 @@ struct _GstThread {
|
|||
pthread_t thread_id; /* id of the thread, if any */
|
||||
GMutex *lock; /* thread lock/condititon pair... */
|
||||
GCond *cond; /* used to control the thread */
|
||||
|
||||
gint transition; /* the current state transition */
|
||||
};
|
||||
|
||||
struct _GstThreadClass {
|
||||
|
|
|
@ -412,8 +412,6 @@ gst_media_play_frame_displayed (GstPlay *play,
|
|||
size = gst_play_get_media_size (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) {
|
||||
gdk_threads_enter ();
|
||||
gst_media_play_update_status_area (mplay, current_time, total_time);
|
||||
|
|
|
@ -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(0,A, GST_ELEMENT_NAME(queue))
|
||||
#else
|
||||
#define STATUS(A)
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
SUBDIRS = sched eos
|
||||
|
||||
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
|
||||
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