From f0326eea5550d26d9d7640578db7780f5e67cad1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sat, 30 Mar 2002 17:05:03 +0000 Subject: [PATCH] - Remove the propsprivate header file Original commit message from CVS: - Remove the propsprivate header file - Added new API for properties. - Moved the clock distribution to the scheduler. - Removed the lock from GstCaps - Added boxed types for Caps/Props - Simplified the clock, new systemclock implementation - Removed deprecated element_info/send_event functions - First step at exposing more info in the pad_connect functions - Queue cleanup - Make the scheduler aware of other schedulers inside it - Added the _SELF_SCHEDULABLE flag to gstthread - Removed _get_widget from _utils, changed to new props API - Make fakesink sync on timestamps when requested - Removed the offset notify from filesrc - Added a fast scheduler - some scheduler cleanups. --- gst/Makefile.am | 7 +- gst/elements/gstfakesink.c | 34 +- gst/elements/gstfakesink.h | 11 +- gst/elements/gstfakesrc.c | 1 + gst/elements/gstfakesrc.h | 3 +- gst/elements/gstfilesrc.c | 8 +- gst/elements/gsttee.c | 2 +- gst/gst.h | 1 - gst/gstbin.c | 140 +---- gst/gstbin.h | 9 - gst/gstcaps.c | 20 +- gst/gstcaps.h | 22 +- gst/gstclock.c | 288 +++++++++- gst/gstclock.h | 27 +- gst/gstelement.c | 70 +-- gst/gstelement.h | 8 +- gst/gstpad.c | 10 +- gst/gstpad.h | 10 +- gst/gstprops.c | 539 +++++++++++------- gst/gstprops.h | 112 ++-- gst/gstpropsprivate.h | 62 -- gst/gstqueue.c | 14 +- gst/gstscheduler.c | 214 ++++++- gst/gstscheduler.h | 36 +- gst/gstsystemclock.c | 95 +--- gst/gstsystemclock.h | 3 - gst/gstthread.c | 1 + gst/gstutils.c | 107 ++-- gst/gstutils.h | 3 +- gst/schedulers/Makefile.am | 7 +- gst/schedulers/gstbasicscheduler.c | 32 +- gst/schedulers/gstfastscheduler.c | 1095 ++++++++++++++++++++++++++++++++++++ plugins/elements/gstfakesink.c | 34 +- plugins/elements/gstfakesink.h | 11 +- plugins/elements/gstfakesrc.c | 1 + plugins/elements/gstfakesrc.h | 3 +- plugins/elements/gstfilesrc.c | 8 +- plugins/elements/gstqueue.c | 14 +- plugins/elements/gsttee.c | 2 +- 39 files changed, 2259 insertions(+), 805 deletions(-) delete mode 100644 gst/gstpropsprivate.h create mode 100644 gst/schedulers/gstfastscheduler.c diff --git a/gst/Makefile.am b/gst/Makefile.am index f802393..ac40feb 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -145,19 +145,18 @@ libgstreamerinclude_HEADERS = \ noinst_HEADERS = \ gst_private.h \ gstarch.h \ - gstpropsprivate.h \ cothreads.h libgstreamer_la_CFLAGS = -D_GNU_SOURCE -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\" \ $(LIBGST_CFLAGS) \ -D_GNU_SOURCE \ -DG_LOG_DOMAIN=g_log_domain_gstreamer \ - -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\" + -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\" # the compiler shoots cothreads.c in the head at -O6 -libcothreads_la_CFLAGS = $(libgstreamer_la_CFLAGS) -O2 +libcothreads_la_CFLAGS = $(libgstreamer_la_CFLAGS) -O2 libgstreamer_la_LIBADD = $(LIBGST_LIBS) -libgstreamer_la_LDFLAGS = @GST_LT_LDFLAGS@ -version-info @GST_LIBVERSION@ +libgstreamer_la_LDFLAGS = @GST_LT_LDFLAGS@ -version-info @GST_LIBVERSION@ EXTRA_DIST = ROADMAP diff --git a/gst/elements/gstfakesink.c b/gst/elements/gstfakesink.c index c6d0198..21f4c92 100644 --- a/gst/elements/gstfakesink.c +++ b/gst/elements/gstfakesink.c @@ -46,6 +46,7 @@ enum { ARG_NUM_SINKS, ARG_SILENT, ARG_DUMP, + ARG_SYNC, ARG_LAST_MESSAGE, }; @@ -60,6 +61,7 @@ GST_PADTEMPLATE_FACTORY (fakesink_sink_factory, static void gst_fakesink_class_init (GstFakeSinkClass *klass); static void gst_fakesink_init (GstFakeSink *fakesink); +static void gst_fakesink_set_clock (GstElement *element, GstClock *clock); static GstPad* gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused); @@ -106,12 +108,14 @@ gst_fakesink_class_init (GstFakeSinkClass *klass) parent_class = g_type_class_ref (GST_TYPE_ELEMENT); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS, - g_param_spec_int ("num_sinks", "num_sinks", "num_sinks", + g_param_spec_int ("num_sinks", "Number of sinks", "The number of sinkpads", 1, G_MAXINT, 1, G_PARAM_READABLE)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE, g_param_spec_string ("last_message", "last_message", "last_message", NULL, G_PARAM_READABLE)); - + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SYNC, + g_param_spec_boolean("sync","Sync","Sync on the clock", + FALSE, G_PARAM_READWRITE)); /* CHECKME */ gst_element_class_install_std_props ( GST_ELEMENT_CLASS (klass), @@ -141,9 +145,22 @@ gst_fakesink_init (GstFakeSink *fakesink) fakesink->silent = FALSE; fakesink->dump = FALSE; + fakesink->sync = FALSE; fakesink->last_message = NULL; + + GST_ELEMENT (fakesink)->setclockfunc = gst_fakesink_set_clock; } +static void +gst_fakesink_set_clock (GstElement *element, GstClock *clock) +{ + GstFakeSink *sink; + + sink = GST_FAKESINK (element); + + sink->clock = clock; +} + static GstPad* gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused) { @@ -183,6 +200,9 @@ gst_fakesink_set_property (GObject *object, guint prop_id, const GValue *value, case ARG_DUMP: sink->dump = g_value_get_boolean (value); break; + case ARG_SYNC: + sink->sync = g_value_get_boolean (value); + break; default: break; } @@ -208,6 +228,9 @@ gst_fakesink_get_property (GObject *object, guint prop_id, GValue *value, GParam case ARG_DUMP: g_value_set_boolean (value, sink->dump); break; + case ARG_SYNC: + g_value_set_boolean (value, sink->sync); + break; case ARG_LAST_MESSAGE: g_value_set_string (value, sink->last_message); break; @@ -228,9 +251,12 @@ gst_fakesink_chain (GstPad *pad, GstBuffer *buf) fakesink = GST_FAKESINK (gst_pad_get_parent (pad)); + if (fakesink->sync) { + gst_element_clock_wait (GST_ELEMENT (fakesink), fakesink->clock, GST_BUFFER_TIMESTAMP (buf)); + } + if (!fakesink->silent) { - if (fakesink->last_message) - g_free (fakesink->last_message); + g_free (fakesink->last_message); fakesink->last_message = g_strdup_printf ("chain ******* (%s:%s)< (%d bytes, %lld) %p", GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf); diff --git a/gst/elements/gstfakesink.h b/gst/elements/gstfakesink.h index 4bc3bb5..6c38ae3 100644 --- a/gst/elements/gstfakesink.h +++ b/gst/elements/gstfakesink.h @@ -52,11 +52,14 @@ typedef struct _GstFakeSink GstFakeSink; typedef struct _GstFakeSinkClass GstFakeSinkClass; struct _GstFakeSink { - GstElement element; + GstElement element; - gboolean silent; - gboolean dump; - gchar *last_message; + gboolean silent; + gboolean dump; + gboolean sync; + GstClock *clock; + + gchar *last_message; }; struct _GstFakeSinkClass { diff --git a/gst/elements/gstfakesrc.c b/gst/elements/gstfakesrc.c index 18ef726..9686385 100644 --- a/gst/elements/gstfakesrc.c +++ b/gst/elements/gstfakesrc.c @@ -321,6 +321,7 @@ gst_fakesrc_event_handler (GstPad *pad, GstEvent *event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: src->buffer_count = GST_EVENT_SEEK_OFFSET (event); + if (!GST_EVENT_SEEK_FLUSH (event)) { gst_event_free (event); break; diff --git a/gst/elements/gstfakesrc.h b/gst/elements/gstfakesrc.h index 7f916ca..f4a0e67 100644 --- a/gst/elements/gstfakesrc.h +++ b/gst/elements/gstfakesrc.h @@ -105,7 +105,8 @@ struct _GstFakeSrc { gboolean silent; gboolean dump; gboolean need_flush; - gchar *last_message; + + gchar *last_message; }; struct _GstFakeSrcClass { diff --git a/gst/elements/gstfilesrc.c b/gst/elements/gstfilesrc.c index 3f97331..c50e8c5 100644 --- a/gst/elements/gstfilesrc.c +++ b/gst/elements/gstfilesrc.c @@ -78,7 +78,7 @@ GstElementDetails gst_filesrc_details = { "(C) 1999", }; -/*#define fs_print(format,args...) g_print(format, ## args)*/ +/*#define fs_print(format,args...) g_print(format, ## args) */ #define fs_print(format,args...) /* FileSrc signals and args */ @@ -549,7 +549,7 @@ gst_filesrc_get (GstPad *pad) /* we're done, return the buffer */ src->curoffset += GST_BUFFER_SIZE(buf); - g_object_notify (G_OBJECT (src), "offset"); + //g_object_notify (G_OBJECT (src), "offset"); return buf; } @@ -590,7 +590,7 @@ gst_filesrc_open_file (GstFileSrc *src) /* now notify of the changes */ g_object_freeze_notify (G_OBJECT (src)); g_object_notify (G_OBJECT (src), "filesize"); - g_object_notify (G_OBJECT (src), "offset"); + //g_object_notify (G_OBJECT (src), "offset"); g_object_thaw_notify (G_OBJECT (src)); GST_FLAG_SET (src, GST_FILESRC_OPEN); @@ -614,7 +614,7 @@ gst_filesrc_close_file (GstFileSrc *src) /* and notify that things changed */ g_object_freeze_notify (G_OBJECT (src)); g_object_notify (G_OBJECT (src), "filesize"); - g_object_notify (G_OBJECT (src), "offset"); + //g_object_notify (G_OBJECT (src), "offset"); g_object_thaw_notify (G_OBJECT (src)); if (src->mapbuf) diff --git a/gst/elements/gsttee.c b/gst/elements/gsttee.c index ea38edc..2ea7428 100644 --- a/gst/elements/gsttee.c +++ b/gst/elements/gsttee.c @@ -181,7 +181,7 @@ gst_tee_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar GList *pads; g_return_val_if_fail (GST_IS_TEE (element), NULL); - + if (templ->direction != GST_PAD_SRC) { g_warning ("gsttee: request new pad that is not a SRC pad\n"); return NULL; diff --git a/gst/gst.h b/gst/gst.h index 620bafa..85d1c60 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/gst/gstbin.c b/gst/gstbin.c index cc3c3f6..7c50c6b 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -152,78 +152,16 @@ gst_bin_new (const gchar * name) return gst_elementfactory_make ("bin", name); } -static inline void -gst_bin_reset_element_sched (GstElement * element, GstScheduler * sched) -{ - GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "resetting element's scheduler"); - - gst_element_set_sched (element, sched); -} - - -static void -gst_bin_get_clock_elements (GstBin *bin, GList **needing, GList **providing) -{ - GList *children = gst_bin_get_list (bin); - - while (children) { - GstElement *child = GST_ELEMENT (children->data); - - if (GST_IS_BIN (child)) { - gst_bin_get_clock_elements (GST_BIN (child), needing, providing); - } - if (child->getclockfunc) { - *providing = g_list_prepend (*providing, child); - } - if (child->setclockfunc) { - *needing = g_list_prepend (*needing, child); - } - - children = g_list_next (children); - } -} - -static void -gst_bin_distribute_clock (GstBin *bin, GList *needing, GstClock *clock) -{ - while (needing) { - GST_DEBUG (GST_CAT_CLOCK, "setting clock on %s", GST_ELEMENT_NAME (needing->data)); - gst_element_set_clock (GST_ELEMENT (needing->data), clock); - - needing = g_list_next (needing); - } -} - -static void -gst_bin_distribute_clocks (GstBin *bin) -{ - GList *needing = NULL, *providing = NULL; - GstClock *clock; - - gst_bin_get_clock_elements (bin, &needing, &providing); - - if (GST_FLAG_IS_SET (bin, GST_BIN_FLAG_FIXED_CLOCK)) { - clock = bin->clock; - } - else if (providing) { - clock = gst_element_get_clock (GST_ELEMENT (providing->data)); - } - else { - GST_DEBUG (GST_CAT_CLOCK, "no clock provided, using default clock"); - clock = gst_system_clock_obtain (); - } - - GST_BIN_CLOCK (bin) = clock; - gst_bin_distribute_clock (bin, needing, clock); -} - GstClock* gst_bin_get_clock (GstBin *bin) { g_return_val_if_fail (bin != NULL, NULL); g_return_val_if_fail (GST_IS_BIN (bin), NULL); - return GST_BIN_CLOCK (bin); + if (GST_ELEMENT_SCHED (bin)) + return gst_scheduler_get_clock (GST_ELEMENT_SCHED (bin)); + + return NULL; } void @@ -232,8 +170,8 @@ gst_bin_use_clock (GstBin *bin, GstClock *clock) g_return_if_fail (bin != NULL); g_return_if_fail (GST_IS_BIN (bin)); - GST_FLAG_SET (bin, GST_BIN_FLAG_FIXED_CLOCK); - GST_BIN_CLOCK (bin) = clock; + if (GST_ELEMENT_SCHED (bin)) + gst_scheduler_use_clock (GST_ELEMENT_SCHED (bin), clock); } void @@ -242,12 +180,12 @@ gst_bin_auto_clock (GstBin *bin) g_return_if_fail (bin != NULL); g_return_if_fail (GST_IS_BIN (bin)); - GST_FLAG_UNSET (bin, GST_BIN_FLAG_FIXED_CLOCK); - GST_BIN_CLOCK (bin) = NULL; + if (GST_ELEMENT_SCHED (bin)) + gst_scheduler_auto_clock (GST_ELEMENT_SCHED (bin)); } static void -gst_bin_set_element_sched (GstElement * element, GstScheduler * sched) +gst_bin_set_element_sched (GstElement *element, GstScheduler *sched) { GList *children; GstElement *child; @@ -264,6 +202,7 @@ gst_bin_set_element_sched (GstElement * element, GstScheduler * sched) if (GST_IS_BIN (element)) { if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) { GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not resetting"); + gst_scheduler_add_scheduler (sched, GST_ELEMENT_SCHED (element)); return; } @@ -278,7 +217,6 @@ gst_bin_set_element_sched (GstElement * element, GstScheduler * sched) gst_bin_set_element_sched (child, sched); } - } /* otherwise, if it's just a regular old element */ else { @@ -288,7 +226,7 @@ gst_bin_set_element_sched (GstElement * element, GstScheduler * sched) static void -gst_bin_unset_element_sched (GstElement * element) +gst_bin_unset_element_sched (GstElement *element, GstScheduler *sched) { GList *children; GstElement *child; @@ -302,7 +240,7 @@ gst_bin_unset_element_sched (GstElement * element) return; } - GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from it sched %p", + GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from its sched %p", GST_ELEMENT_NAME (element), GST_ELEMENT_SCHED (element)); /* if it's actually a Bin */ @@ -311,20 +249,21 @@ gst_bin_unset_element_sched (GstElement * element) if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) { GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not unsetting sched"); + if (sched) { + gst_scheduler_remove_scheduler (sched, GST_ELEMENT_SCHED (element)); + } return; } - - gst_scheduler_remove_element (GST_ELEMENT_SCHED (element), element); - /* for each child, remove them from their schedule */ children = GST_BIN (element)->children; while (children) { child = GST_ELEMENT (children->data); children = g_list_next (children); - gst_bin_unset_element_sched (child); + gst_bin_unset_element_sched (child, sched); } + gst_scheduler_remove_element (GST_ELEMENT_SCHED (element), element); } /* otherwise, if it's just a regular old element */ else { @@ -372,10 +311,11 @@ gst_bin_add_many (GstBin *bin, GstElement *element_1, ...) * add a reference. */ void -gst_bin_add (GstBin * bin, GstElement * element) +gst_bin_add (GstBin *bin, GstElement *element) { gint state_idx = 0; GstElementState state; + GstScheduler *sched; g_return_if_fail (bin != NULL); g_return_if_fail (GST_IS_BIN (bin)); @@ -409,11 +349,9 @@ gst_bin_add (GstBin * bin, GstElement * element) /* now we have to deal with manager stuff * we can only do this if there's a scheduler: * if we're not a manager, and aren't attached to anything, we have no sched (yet) */ - if (GST_IS_BIN (element) && GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) { - GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is a manager"); - } - else if (GST_ELEMENT_SCHED (bin) != NULL) { - gst_bin_set_element_sched (element, GST_ELEMENT_SCHED (bin)); + sched = GST_ELEMENT_SCHED (bin); + if (sched) { + gst_bin_set_element_sched (element, sched); } GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child \"%s\"", GST_ELEMENT_NAME (element)); @@ -429,7 +367,7 @@ gst_bin_add (GstBin * bin, GstElement * element) * Remove the element from its associated bin, unparenting as well. */ void -gst_bin_remove (GstBin * bin, GstElement * element) +gst_bin_remove (GstBin *bin, GstElement *element) { gint state_idx = 0; GstElementState state; @@ -456,7 +394,7 @@ gst_bin_remove (GstBin * bin, GstElement * element) } /* remove this element from the list of managed elements */ - gst_bin_unset_element_sched (element); + gst_bin_unset_element_sched (element, GST_ELEMENT_SCHED (bin)); /* now remove the element from the list of elements */ bin->children = g_list_remove (bin->children, element); @@ -504,7 +442,7 @@ gst_bin_child_state_change (GstBin *bin, GstElementState oldstate, GstElementSta GST_LOCK (bin); bin->child_states[old_idx]--; bin->child_states[new_idx]++; - + for (i = GST_NUM_STATES - 1; i >= 0; i--) { if (bin->child_states[i] != 0) { gint state = (1 << i); @@ -512,7 +450,9 @@ gst_bin_child_state_change (GstBin *bin, GstElementState oldstate, GstElementSta GST_INFO (GST_CAT_STATES, "bin %s need state change to %s", GST_ELEMENT_NAME (bin), gst_element_statename (state)); GST_STATE_PENDING (bin) = state; + GST_UNLOCK (bin); gst_bin_change_state_norecurse (bin); + return; } break; } @@ -542,7 +482,11 @@ gst_bin_change_state (GstElement * element) GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing childrens' state from %s to %s", gst_element_statename (old_state), gst_element_statename (pending)); + if (pending == GST_STATE_VOID_PENDING) + return GST_STATE_SUCCESS; + children = bin->children; + while (children) { child = GST_ELEMENT (children->data); children = g_list_next (children); @@ -569,28 +513,6 @@ gst_bin_change_state (GstElement * element) } } - if (GST_ELEMENT_SCHED (bin) != NULL && GST_ELEMENT_PARENT (bin) == NULL) { - switch (transition) { - case GST_STATE_NULL_TO_READY: - gst_bin_distribute_clocks (bin); - break; - case GST_STATE_READY_TO_PAUSED: - if (GST_BIN_CLOCK (bin)) - gst_clock_reset (GST_BIN_CLOCK (bin)); - break; - case GST_STATE_PAUSED_TO_PLAYING: - gst_bin_distribute_clocks (bin); - if (GST_BIN_CLOCK (bin)) - gst_clock_activate (GST_BIN_CLOCK (bin), TRUE); - break; - case GST_STATE_PLAYING_TO_PAUSED: - if (GST_BIN_CLOCK (bin)) - gst_clock_activate (GST_BIN_CLOCK (bin), FALSE); - break; - } - } - - GST_INFO_ELEMENT (GST_CAT_STATES, element, "done changing bin's state from %s to %s, now in %s", gst_element_statename (old_state), gst_element_statename (pending), diff --git a/gst/gstbin.h b/gst/gstbin.h index 016ddec..4e433ea 100644 --- a/gst/gstbin.h +++ b/gst/gstbin.h @@ -48,10 +48,6 @@ extern GType _gst_bin_type; # define GST_BIN_CLASS GST_BIN_CLASS_CAST #endif -#define GST_BIN_CLOCK_PROVIDERS(bin) (GST_BIN(bin)->clock_providers) -#define GST_BIN_CLOCK_RECEIVERS(bin) (GST_BIN(bin)->clock_receivers) -#define GST_BIN_CLOCK(bin) (GST_BIN(bin)->clock) - typedef enum { /* this bin is a manager of child elements, i.e. a pipeline or thread */ GST_BIN_FLAG_MANAGER = GST_ELEMENT_FLAG_LAST, @@ -82,8 +78,6 @@ struct _GstBin { GstElementState child_states[GST_NUM_STATES]; - GstClock *clock; - gpointer sched_private; }; @@ -128,9 +122,6 @@ void gst_bin_auto_clock (GstBin *bin); /* one of our childs signaled a state change */ void gst_bin_child_state_change (GstBin *bin, GstElementState oldstate, GstElementState newstate, GstElement *child); -/* one of our childs signaled an error */ -void gst_bin_child_error (GstBin *bin, GstElement *child); - #ifdef __cplusplus } diff --git a/gst/gstcaps.c b/gst/gstcaps.c index 83f1065..cb2707e 100644 --- a/gst/gstcaps.c +++ b/gst/gstcaps.c @@ -26,11 +26,11 @@ #include "gstcaps.h" #include "gsttype.h" -#include "gstpropsprivate.h" - static GMemChunk *_gst_caps_chunk; static GMutex *_gst_caps_chunk_lock; +GType _gst_caps_type; + void _gst_caps_initialize (void) { @@ -38,6 +38,11 @@ _gst_caps_initialize (void) sizeof (GstCaps), sizeof (GstCaps) * 256, G_ALLOC_AND_FREE); _gst_caps_chunk_lock = g_mutex_new (); + + _gst_caps_type = g_boxed_type_register_static ("GstCaps", + (GBoxedCopyFunc) gst_caps_ref, + (GBoxedFreeFunc) gst_caps_unref); + } static guint16 @@ -104,7 +109,6 @@ gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props) caps->properties = props; caps->next = NULL; caps->refcount = 1; - caps->lock = g_mutex_new (); if (props) caps->fixed = props->fixed; else @@ -128,11 +132,8 @@ gst_caps_destroy (GstCaps *caps) if (caps == NULL) return; - GST_CAPS_LOCK (caps); next = caps->next; - GST_CAPS_UNLOCK (caps); - g_mutex_free (caps->lock); gst_props_unref (caps->properties); g_free (caps->name); g_mutex_lock (_gst_caps_chunk_lock); @@ -189,11 +190,9 @@ gst_caps_unref (GstCaps *caps) g_return_val_if_fail (caps->refcount > 0, NULL); - GST_CAPS_LOCK (caps); caps->refcount--; zero = (caps->refcount == 0); next = &caps->next; - GST_CAPS_UNLOCK (caps); if (*next) *next = gst_caps_unref (*next); @@ -218,9 +217,7 @@ gst_caps_ref (GstCaps *caps) { g_return_val_if_fail (caps != NULL, NULL); - GST_CAPS_LOCK (caps); caps->refcount++; - GST_CAPS_UNLOCK (caps); return caps; } @@ -296,9 +293,7 @@ gst_caps_copy_on_write (GstCaps *caps) g_return_val_if_fail (caps != NULL, NULL); - GST_CAPS_LOCK (caps); needcopy = (caps->refcount > 1); - GST_CAPS_UNLOCK (caps); if (needcopy) { new = gst_caps_copy (caps); @@ -798,7 +793,6 @@ gst_caps_load_thyself (xmlNodePtr parent) g_mutex_unlock (_gst_caps_chunk_lock); caps->refcount = 1; - caps->lock = g_mutex_new (); caps->next = NULL; caps->fixed = TRUE; diff --git a/gst/gstcaps.h b/gst/gstcaps.h index 39ee56d..01d5d6a 100644 --- a/gst/gstcaps.h +++ b/gst/gstcaps.h @@ -30,13 +30,14 @@ typedef struct _GstCaps GstCaps; +extern GType _gst_caps_type; + +#define GST_TYPE_CAPS (_get_caps_type) + + #define GST_CAPS(caps) \ ((GstCaps *)(caps)) -#define GST_CAPS_LOCK(caps) (g_mutex_lock(GST_CAPS(caps)->lock)) -#define GST_CAPS_TRYLOCK(caps) (g_mutex_trylock(GST_CAPS(caps)->lock)) -#define GST_CAPS_UNLOCK(caps) (g_mutex_unlock(GST_CAPS(caps)->lock)) - #define GST_CAPS_IS_FIXED(caps) ((caps)->fixed) #define GST_CAPS_IS_CHAINED(caps) ((caps)->next) @@ -45,7 +46,6 @@ struct _GstCaps { guint16 id; /* type id (major type) */ guint refcount; - GMutex *lock; /* global lock for this capability */ gboolean fixed; /* this caps doesn't contain variable properties */ GstProps *properties; /* properties for this capability */ @@ -104,14 +104,16 @@ GstCaps* gst_caps_set_props (GstCaps *caps, GstProps *props); GstProps* gst_caps_get_props (GstCaps *caps); #define gst_caps_set(caps, name, args...) gst_props_set ((caps)->properties, name, args) +#define gst_caps_get(caps, name, args...) gst_props_get ((caps)->properties, name, args) -#define gst_caps_get_int(caps, name) gst_props_get_int ((caps)->properties, name) -#define gst_caps_get_float(caps, name) gst_props_get_float ((caps)->properties, name) -#define gst_caps_get_fourcc_int(caps, name) gst_props_get_fourcc_int ((caps)->properties, name) -#define gst_caps_get_boolean(caps, name) gst_props_get_boolean ((caps)->properties, name) -#define gst_caps_get_string(caps, name) gst_props_get_string ((caps)->properties, name) +#define gst_caps_get_int(caps,name,res) gst_props_entry_get_int(gst_props_get_entry((caps)->properties,name),res) +#define gst_caps_get_float(caps,name,res) gst_props_entry_get_float(gst_props_get_entry((caps)->properties,name),res) +#define gst_caps_get_fourcc_int(caps,name,res) gst_props_entry_get_fourcc_int(gst_props_get_entry((caps)->properties,name),res) +#define gst_caps_get_boolean(caps,name,res) gst_props_entry_get_boolean(gst_props_get_entry((caps)->properties,name),res) +#define gst_caps_get_string(caps,name,res) gst_props_entry_get_string(gst_props_get_entry((caps)->properties,name),res) #define gst_caps_has_property(caps, name) gst_props_has_property ((caps)->properties, name) +#define gst_caps_has_property_typed(caps, name) gst_props_has_property_typed ((caps)->properties, name) #define gst_caps_has_fixed_property(caps, name) gst_props_has_fixed_property ((caps)->properties, name) GstCaps* gst_caps_get_by_name (GstCaps *caps, const gchar *name); diff --git a/gst/gstclock.c b/gst/gstclock.c index fb1c2ff..e96c717 100644 --- a/gst/gstclock.c +++ b/gst/gstclock.c @@ -29,13 +29,80 @@ #define CLASS(clock) GST_CLOCK_CLASS (G_OBJECT_GET_CLASS (clock)) +static GMemChunk *_gst_clock_entries_chunk; +static GMutex *_gst_clock_entries_chunk_lock; +static GList *_gst_clock_entries_pool; static void gst_clock_class_init (GstClockClass *klass); static void gst_clock_init (GstClock *clock); + static GstObjectClass *parent_class = NULL; /* static guint gst_clock_signals[LAST_SIGNAL] = { 0 }; */ +typedef struct _GstClockEntry GstClockEntry; + +static void gst_clock_free_entry (GstClock *clock, GstClockEntry *entry); + +typedef enum { + GST_ENTRY_OK, + GST_ENTRY_RESTART, +} GstEntryStatus; + +struct _GstClockEntry { + GstClockTime time; + GstEntryStatus status; + GstClockCallback func; + gpointer user_data; + GMutex *lock; + GCond *cond; +}; + +#define GST_CLOCK_ENTRY(entry) ((GstClockEntry *)(entry)) +#define GST_CLOCK_ENTRY_TIME(entry) (((GstClockEntry *)(entry))->time) +#define GST_CLOCK_ENTRY_LOCK(entry) (g_mutex_lock ((entry)->lock)) +#define GST_CLOCK_ENTRY_UNLOCK(entry) (g_mutex_unlock ((entry)->lock)) +#define GST_CLOCK_ENTRY_SIGNAL(entry) (g_cond_signal ((entry)->cond)) +#define GST_CLOCK_ENTRY_WAIT(entry) (g_cond_wait (entry->cond, entry->lock)) +#define GST_CLOCK_ENTRY_TIMED_WAIT(entry, time) (g_cond_timed_wait (entry->cond, entry->lock, (time))) + +static GstClockEntry* +gst_clock_entry_new (GstClockTime time, + GstClockCallback func, gpointer user_data) +{ + GstClockEntry *entry; + + g_mutex_lock (_gst_clock_entries_chunk_lock); + if (_gst_clock_entries_pool) { + entry = GST_CLOCK_ENTRY (_gst_clock_entries_pool->data); + + _gst_clock_entries_pool = g_list_remove (_gst_clock_entries_pool, entry); + g_mutex_unlock (_gst_clock_entries_chunk_lock); + } + else { + entry = g_mem_chunk_alloc (_gst_clock_entries_chunk); + g_mutex_unlock (_gst_clock_entries_chunk_lock); + + entry->lock = g_mutex_new (); + entry->cond = g_cond_new (); + } + entry->time = time; + entry->func = func; + entry->user_data = user_data; + + return entry; +} + +static gint +clock_compare_func (gconstpointer a, + gconstpointer b) +{ + GstClockEntry *entry1 = (GstClockEntry *)a; + GstClockEntry *entry2 = (GstClockEntry *)b; + + return (entry1->time - entry2->time); +} + GType gst_clock_get_type (void) { @@ -43,19 +110,19 @@ gst_clock_get_type (void) if (!clock_type) { static const GTypeInfo clock_info = { - sizeof (GstObjectClass), + sizeof (GstClockClass), NULL, NULL, (GClassInitFunc) gst_clock_class_init, NULL, NULL, - sizeof (GstObject), + sizeof (GstClock), 4, (GInstanceInitFunc) gst_clock_init, NULL }; clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock", - &clock_info, G_TYPE_FLAG_ABSTRACT); + &clock_info, G_TYPE_FLAG_ABSTRACT); } return clock_type; } @@ -70,6 +137,12 @@ gst_clock_class_init (GstClockClass *klass) gstobject_class = (GstObjectClass*) klass; parent_class = g_type_class_ref (GST_TYPE_OBJECT); + + _gst_clock_entries_chunk = g_mem_chunk_new ("GstClockEntries", + sizeof (GstClockEntry), sizeof (GstClockEntry) * 32, + G_ALLOC_AND_FREE); + _gst_clock_entries_chunk_lock = g_mutex_new (); + _gst_clock_entries_pool = NULL; } static void @@ -78,37 +151,66 @@ gst_clock_init (GstClock *clock) clock->speed = 1.0; clock->active = FALSE; clock->start_time = 0; + clock->last_time = 0; + clock->entries = NULL; + clock->async_supported = FALSE; clock->active_mutex = g_mutex_new (); clock->active_cond = g_cond_new (); } +gboolean +gst_clock_async_supported (GstClock *clock) +{ + g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE); + + return clock->async_supported; +} + + void gst_clock_reset (GstClock *clock) { + GstClockTime time = 0LL; + g_return_if_fail (GST_IS_CLOCK (clock)); - clock->start_time = 0; - clock->active = FALSE; + if (CLASS (clock)->get_internal_time) { + time = CLASS (clock)->get_internal_time (clock); + } - if (CLASS (clock)->reset) - CLASS (clock)->reset (clock); + GST_LOCK (clock); + clock->active = FALSE; + clock->start_time = time; + clock->last_time = 0LL; + GST_UNLOCK (clock); } void gst_clock_activate (GstClock *clock, gboolean active) { + GstClockTime time = 0LL; + g_return_if_fail (GST_IS_CLOCK (clock)); clock->active = active; + + if (CLASS (clock)->get_internal_time) { + time = CLASS (clock)->get_internal_time (clock); + } - if (CLASS (clock)->activate) - CLASS (clock)->activate (clock, active); + GST_LOCK (clock); + if (active) { + clock->start_time = time - clock->last_time;; + } + else { + clock->last_time = time - clock->start_time; + } + GST_UNLOCK (clock); g_mutex_lock (clock->active_mutex); - g_cond_signal (clock->active_cond); + g_cond_broadcast (clock->active_cond); g_mutex_unlock (clock->active_mutex); - } gboolean @@ -119,40 +221,166 @@ gst_clock_is_active (GstClock *clock) return clock->active; } -void -gst_clock_set_time (GstClock *clock, GstClockTime time) -{ - g_return_if_fail (GST_IS_CLOCK (clock)); - - if (CLASS (clock)->set_time) - CLASS (clock)->set_time (clock, time); -} - GstClockTime gst_clock_get_time (GstClock *clock) { + GstClockTime ret = 0LL; + g_return_val_if_fail (GST_IS_CLOCK (clock), 0LL); - if (CLASS (clock)->get_time) - return CLASS (clock)->get_time (clock); + if (!clock->active) { + /* clock is not activen return previous time */ + ret = clock->last_time; + } + else { + if (CLASS (clock)->get_internal_time) { + ret = CLASS (clock)->get_internal_time (clock) - clock->start_time; + } + /* make sure the time is increasing, else return last_time */ + if (ret < clock->last_time) { + ret = clock->last_time; + } + else { + clock->last_time = ret; + } + } - return 0LL; + return ret; } -GstClockReturn -gst_clock_wait (GstClock *clock, GstClockTime time) +static GstClockID +gst_clock_wait_async_func (GstClock *clock, GstClockTime time, + GstClockCallback func, gpointer user_data) { - g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_STOPPED); + GstClockEntry *entry = NULL; + g_return_val_if_fail (GST_IS_CLOCK (clock), NULL); if (!clock->active) { g_mutex_lock (clock->active_mutex); g_cond_wait (clock->active_cond, clock->active_mutex); g_mutex_unlock (clock->active_mutex); } - if (CLASS (clock)->wait) - return CLASS (clock)->wait (clock, time); - return GST_CLOCK_TIMEOUT; + entry = gst_clock_entry_new (time, func, user_data); + + GST_LOCK (clock); + clock->entries = g_list_insert_sorted (clock->entries, entry, clock_compare_func); + GST_UNLOCK (clock); + + return entry; +} + +GstClockReturn +gst_clock_wait (GstClock *clock, GstClockTime time) +{ + GstClockID id; + GstClockReturn res; + + g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_STOPPED); + + id = gst_clock_wait_async_func (clock, time, NULL, NULL); + res = gst_clock_wait_id (clock, id); + + return res; +} + +GstClockID +gst_clock_wait_async (GstClock *clock, GstClockTime time, + GstClockCallback func, gpointer user_data) +{ + g_return_val_if_fail (GST_IS_CLOCK (clock), NULL); + + if (clock->async_supported) { + return gst_clock_wait_async_func (clock, time, func, user_data); + } + return NULL; +} + +static void +gst_clock_unlock_func (GstClock *clock, GstClockTime time, GstClockID id, gpointer user_data) +{ + GstClockEntry *entry = (GstClockEntry *) id; + + GST_CLOCK_ENTRY_LOCK (entry); + GST_CLOCK_ENTRY_SIGNAL (entry); + GST_CLOCK_ENTRY_UNLOCK (entry); +} + +GstClockReturn +gst_clock_wait_id (GstClock *clock, GstClockID id) +{ + GstClockReturn res = GST_CLOCK_TIMEOUT; + GstClockEntry *entry = (GstClockEntry *) id; + GstClockTime current_real, current, target; + GTimeVal timeval; + + g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_ERROR); + g_return_val_if_fail (entry, GST_CLOCK_ERROR); + + current = gst_clock_get_time (clock); + + g_get_current_time (&timeval); + current_real = GST_TIMEVAL_TO_TIME (timeval); + + GST_CLOCK_ENTRY_LOCK (entry); + entry->func = gst_clock_unlock_func; + target = GST_CLOCK_ENTRY_TIME (entry) - current + current_real; + + //g_print ("%lld %lld %lld\n", target, current, current_real); + + if (target > current_real) { + timeval.tv_usec = target % 1000000; + timeval.tv_sec = target / 1000000; + + GST_CLOCK_ENTRY_TIMED_WAIT (entry, &timeval); + } + GST_CLOCK_ENTRY_UNLOCK (entry); + + gst_clock_free_entry (clock, entry); + + return res; +} + +GstClockID +gst_clock_get_next_id (GstClock *clock) +{ + GstClockEntry *entry = NULL; + + GST_LOCK (clock); + if (clock->entries) + entry = GST_CLOCK_ENTRY (clock->entries->data); + GST_UNLOCK (clock); + + return (GstClockID *) entry; +} + +GstClockTime +gst_clock_id_get_time (GstClockID id) +{ + return GST_CLOCK_ENTRY_TIME (id); +} + +static void +gst_clock_free_entry (GstClock *clock, GstClockEntry *entry) +{ + GST_LOCK (clock); + clock->entries = g_list_remove (clock->entries, entry); + GST_UNLOCK (clock); + + g_mutex_lock (_gst_clock_entries_chunk_lock); + _gst_clock_entries_pool = g_list_prepend (_gst_clock_entries_pool, entry); + g_mutex_unlock (_gst_clock_entries_chunk_lock); +} + +void +gst_clock_unlock_id (GstClock *clock, GstClockID id) +{ + GstClockEntry *entry = (GstClockEntry *) id; + + if (entry->func) + entry->func (clock, gst_clock_get_time (clock), id, entry->user_data); + + gst_clock_free_entry (clock, entry); } void @@ -172,6 +400,6 @@ gst_clock_get_resolution (GstClock *clock) if (CLASS (clock)->get_resolution) return CLASS (clock)->get_resolution (clock); - return 0LL; + return 1LL; } diff --git a/gst/gstclock.h b/gst/gstclock.h index 08bdd13..027bdec 100644 --- a/gst/gstclock.h +++ b/gst/gstclock.h @@ -65,8 +65,11 @@ struct _GstClock { GstObject object; GstClockTime start_time; + GstClockTime last_time; gdouble speed; gboolean active; + GList *entries; + gboolean async_supported; GMutex *active_mutex; GCond *active_cond; @@ -76,20 +79,8 @@ struct _GstClockClass { GstObjectClass parent_class; /* vtable */ - void (*activate) (GstClock *clock, gboolean active); - void (*reset) (GstClock *clock); - - void (*set_time) (GstClock *clock, GstClockTime time); - GstClockTime (*get_time) (GstClock *clock); - - GstClockReturn (*wait) (GstClock *clock, GstClockTime time); - GstClockID (*wait_async) (GstClock *clock, GstClockTime time, - GstClockCallback func, gpointer user_data); - void (*cancel_wait_async) (GstClock *clock, GstClockID id); - GstClockID (*notify_async) (GstClock *clock, GstClockTime interval, - GstClockCallback func, gpointer user_data); - void (*remove_notify_async) (GstClock *clock, GstClockID id); - + GstClockTime (*get_internal_time) (GstClock *clock); + void (*set_resolution) (GstClock *clock, guint64 resolution); guint64 (*get_resolution) (GstClock *clock); @@ -104,8 +95,8 @@ void gst_clock_get_speed (GstClock *clock, gdouble speed); void gst_clock_activate (GstClock *clock, gboolean active); gboolean gst_clock_is_active (GstClock *clock); void gst_clock_reset (GstClock *clock); +gboolean gst_clock_async_supported (GstClock *clock); -void gst_clock_set_time (GstClock *clock, GstClockTime time); GstClockTime gst_clock_get_time (GstClock *clock); GstClockReturn gst_clock_wait (GstClock *clock, GstClockTime time); @@ -115,6 +106,12 @@ void gst_clock_cancel_wait_async (GstClock *clock, GstClockID id); GstClockID gst_clock_notify_async (GstClock *clock, GstClockTime interval, GstClockCallback func, gpointer user_data); void gst_clock_remove_notify_async (GstClock *clock, GstClockID id); +GstClockReturn gst_clock_wait_id (GstClock *clock, GstClockID id); + +GstClockID gst_clock_get_next_id (GstClock *clock); +void gst_clock_unlock_id (GstClock *clock, GstClockID id); + +GstClockTime gst_clock_id_get_time (GstClockID id); void gst_clock_set_resolution (GstClock *clock, guint64 resolution); guint64 gst_clock_get_resolution (GstClock *clock); diff --git a/gst/gstelement.c b/gst/gstelement.c index 0147a07..1116af1 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -315,8 +315,11 @@ gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time) g_return_val_if_fail (element != NULL, GST_CLOCK_ERROR); g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR); - /* FIXME inform the scheduler */ - return gst_clock_wait (clock, time); + if (GST_ELEMENT_SCHED (element)) { + return gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, clock, time); + } + else + return GST_CLOCK_TIMEOUT; } /** @@ -489,7 +492,9 @@ gst_element_get_pad (GstElement *element, const gchar *name) /* look through the list, matching by name */ walk = element->pads; while (walk) { - GstPad *pad = GST_PAD(walk->data); + GstPad *pad; + + pad = GST_PAD(walk->data); if (!strcmp (GST_PAD_NAME(pad), name)) { GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad)); return pad; @@ -718,6 +723,7 @@ gst_element_request_pad_by_name (GstElement *element, const gchar *name) g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); g_return_val_if_fail (name != NULL, NULL); + if (strstr (name, "%")) { templ = gst_element_get_padtemplate_by_name (element, name); req_name = NULL; @@ -1182,35 +1188,6 @@ gst_element_error (GstElement *element, const gchar *error, ...) } /** - * gst_element_info: - * @element: Element with the info - * @info: String describing the info - * @...: arguments for the string. - * - * This function is used internally by elements to signal an info - * condition. It results in the "info" signal. - */ -void -gst_element_info (GstElement *element, const gchar *info, ...) -{ - g_warning ("The function gst_element_info is gone. Use g_object_notify instead."); -} - - -/** - * gst_element_send_event: - * @element: Element generating the event - * @event: the event to send - * - * This function is deprecated and doesn't work anymore. - */ -void -gst_element_send_event (GstElement *element, GstEvent *event) -{ - g_warning ("The function gst_element_send_event is gone. Use g_object_notify instead."); -} - -/** * gst_element_get_state: * @element: element to get state of * @@ -1258,13 +1235,13 @@ gst_element_set_state (GstElement *element, GstElementState state) g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE); - GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "setting state from %s to %s\n", - gst_element_statename (GST_STATE (element)), - gst_element_statename (state)); - /* start with the current state */ curpending = GST_STATE(element); + GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "setting state from %s to %s\n", + gst_element_statename (curpending), + gst_element_statename (state)); + /* loop until the final requested state is set */ while (GST_STATE (element) != state && GST_STATE (element) != GST_STATE_VOID_PENDING) { /* move the curpending state in the correct direction */ @@ -1277,9 +1254,10 @@ gst_element_set_state (GstElement *element, GstElementState state) /* FIXME: should probably check to see that we don't already have one */ GST_STATE_PENDING (element) = curpending; - if (curpending != state) + if (curpending != state) { GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "intermediate: setting state to %s\n", gst_element_statename (curpending)); + } /* call the state change function so it can set the state */ oclass = CLASS (element); @@ -1297,7 +1275,11 @@ gst_element_set_state (GstElement *element, GstElementState state) /* Last thing we do is verify that a successful state change really * did change the state... */ if (GST_STATE (element) != curpending) { - GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "element claimed state-change success, but state didn't change\n"); + GST_DEBUG_ELEMENT (GST_CAT_STATES, element, + "element claimed state-change success, but state didn't change %s, %s <-> %s\n", + gst_element_statename (GST_STATE (element)), + gst_element_statename (GST_STATE_PENDING (element)), + gst_element_statename (curpending)); return GST_STATE_FAILURE; } break; @@ -1429,9 +1411,6 @@ gst_element_change_state (GstElement *element) } } - g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE], - 0, old_state, GST_STATE (element)); - parent = GST_ELEMENT_PARENT (element); /* tell our parent about the state change */ @@ -1439,6 +1418,9 @@ gst_element_change_state (GstElement *element) gst_bin_child_state_change (GST_BIN (parent), old_state, GST_STATE (element), element); } + g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE], + 0, old_state, GST_STATE (element)); + /* signal the state change in case somebody is waiting for us */ g_mutex_lock (element->state_mutex); g_cond_signal (element->state_cond); @@ -1688,7 +1670,7 @@ gst_element_interrupt (GstElement *element) */ void gst_element_set_sched (GstElement *element, - GstScheduler *sched) + GstScheduler *sched) { g_return_if_fail (GST_IS_ELEMENT (element)); @@ -1727,8 +1709,8 @@ gst_element_get_sched (GstElement *element) * a new loopfunc to be assigned, this should be no problem. */ void -gst_element_set_loop_function(GstElement *element, - GstElementLoopFunction loop) +gst_element_set_loop_function (GstElement *element, + GstElementLoopFunction loop) { g_return_if_fail (GST_IS_ELEMENT (element)); diff --git a/gst/gstelement.h b/gst/gstelement.h index 7440cba..affb351 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -38,7 +38,6 @@ extern "C" { #define GST_NUM_STATES 4 - /* NOTE: this probably should be done with an #ifdef to decide * whether to safe-cast or to just do the non-checking cast. */ @@ -171,7 +170,6 @@ struct _GstElementClass { GstElementStateReturn (*change_state) (GstElement *element); /* request a new pad */ GstPad* (*request_new_pad) (GstElement *element, GstPadTemplate *templ, const gchar* name); - void (*send_event) (GstElement *element, GstEvent *event); }; void gst_element_class_add_padtemplate (GstElementClass *klass, GstPadTemplate *templ); @@ -228,8 +226,7 @@ gboolean gst_element_connect_elements_many (GstElement *element_1, GstElement * void gst_element_set_eos (GstElement *element); -void gst_element_send_event (GstElement *element, GstEvent *event); - +void gst_element_error (GstElement *element, const gchar *error, ...); GstElementState gst_element_get_state (GstElement *element); gint gst_element_set_state (GstElement *element, GstElementState state); @@ -238,9 +235,6 @@ void gst_element_wait_state_change (GstElement *element); const gchar* gst_element_statename (GstElementState state); -void gst_element_info (GstElement *element, const gchar *info, ...); -void gst_element_error (GstElement *element, const gchar *error, ...); - GstElementFactory* gst_element_get_factory (GstElement *element); void gst_element_class_install_std_props (GstElementClass *klass, diff --git a/gst/gstpad.c b/gst/gstpad.c index b6908d9..7b00de0 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -535,7 +535,7 @@ gst_pad_disconnect (GstPad *srcpad, realsink = GST_PAD_REALIZE (sinkpad); g_return_if_fail (GST_RPAD_PEER (realsrc) != NULL); - g_return_if_fail (GST_RPAD_PEER (realsink) != NULL); + g_return_if_fail (GST_RPAD_PEER (realsink) == realsrc); if ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SINK) && (GST_RPAD_DIRECTION (realsink) == GST_PAD_SRC)) { @@ -1013,8 +1013,8 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify) debug_string = "DELAYED"; break; default: - g_warning ("unknown return code from connect function of pad %s:%s", - GST_DEBUG_PAD_NAME (pad)); + g_warning ("unknown return code from connect function of pad %s:%s %d", + GST_DEBUG_PAD_NAME (pad), res); return GST_PAD_CONNECT_REFUSED; } @@ -1337,9 +1337,9 @@ gst_pad_proxy_connect (GstPad *pad, GstCaps *caps) GST_INFO (GST_CAT_CAPS, "proxy connect to pad %s:%s", GST_DEBUG_PAD_NAME (realpad)); - if (peer && !gst_pad_try_set_caps_func (peer, caps, TRUE)) + if (peer && gst_pad_try_set_caps_func (peer, caps, TRUE) < 0) return GST_PAD_CONNECT_REFUSED; - if (!gst_pad_try_set_caps_func (realpad, caps, FALSE)) + if (gst_pad_try_set_caps_func (realpad, caps, FALSE) < 0) return GST_PAD_CONNECT_REFUSED; return GST_PAD_CONNECT_OK; diff --git a/gst/gstpad.h b/gst/gstpad.h index b136f9e..f46418d 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -40,7 +40,7 @@ extern GType _gst_pad_type; extern GType _gst_real_pad_type; extern GType _gst_ghost_pad_type; -/*#define GST_TYPE_PARANOID */ +#define GST_TYPE_PARANOID /* * Pad base class @@ -118,10 +118,10 @@ typedef enum { } GstRegionType; typedef enum { - GST_PAD_CONNECT_REFUSED = 0, - GST_PAD_CONNECT_OK = 1, - GST_PAD_CONNECT_DONE = 2, - GST_PAD_CONNECT_DELAYED = 3, + GST_PAD_CONNECT_REFUSED = -1, + GST_PAD_CONNECT_DELAYED = 0, + GST_PAD_CONNECT_OK = 1, + GST_PAD_CONNECT_DONE = 2, } GstPadConnectReturn; /* this defines the functions used to chain buffers diff --git a/gst/gstprops.c b/gst/gstprops.c index 2650731..f50c5be 100644 --- a/gst/gstprops.c +++ b/gst/gstprops.c @@ -25,7 +25,39 @@ #include "gstlog.h" #include "gstprops.h" -#include "gstpropsprivate.h" + +GType _gst_props_type; + +#define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_TYPE) + +struct _GstPropsEntry { + GQuark propid; + GstPropsType propstype; + + union { + /* flat values */ + gboolean bool_data; + guint32 fourcc_data; + gint int_data; + gfloat float_data; + + /* structured values */ + struct { + GList *entries; + } list_data; + struct { + gchar *string; + } string_data; + struct { + gint min; + gint max; + } int_range_data; + struct { + gfloat min; + gfloat max; + } float_range_data; + } data; +}; static GMemChunk *_gst_props_entries_chunk; static GMutex *_gst_props_entries_chunk_lock; @@ -49,6 +81,11 @@ _gst_props_initialize (void) sizeof (GstProps), sizeof (GstProps) * 256, G_ALLOC_AND_FREE); _gst_props_chunk_lock = g_mutex_new (); + + _gst_props_type = g_boxed_type_register_static ("GstProps", + (GBoxedCopyFunc) gst_props_ref, + (GBoxedFreeFunc) gst_props_unref); + } static void @@ -57,31 +94,31 @@ gst_props_debug_entry (GstPropsEntry *entry) const gchar *name = g_quark_to_string (entry->propid); switch (entry->propstype) { - case GST_PROPS_INT_ID: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: int %d", name, entry->data.int_data); + case GST_PROPS_INT_TYPE: + GST_DEBUG (GST_CAT_PROPERTIES, "%s: int %d\n", name, entry->data.int_data); break; - case GST_PROPS_FLOAT_ID: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: float %f", name, entry->data.float_data); + case GST_PROPS_FLOAT_TYPE: + GST_DEBUG (GST_CAT_PROPERTIES, "%s: float %f\n", name, entry->data.float_data); break; - case GST_PROPS_FOURCC_ID: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: fourcc %4.4s", name, (gchar*)&entry->data.fourcc_data); + case GST_PROPS_FOURCC_TYPE: + GST_DEBUG (GST_CAT_PROPERTIES, "%s: fourcc %4.4s\n", name, (gchar*)&entry->data.fourcc_data); break; - case GST_PROPS_BOOL_ID: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: bool %d", name, entry->data.bool_data); + case GST_PROPS_BOOL_TYPE: + GST_DEBUG (GST_CAT_PROPERTIES, "%s: bool %d\n", name, entry->data.bool_data); break; - case GST_PROPS_STRING_ID: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: string %s", name, entry->data.string_data.string); + case GST_PROPS_STRING_TYPE: + GST_DEBUG (GST_CAT_PROPERTIES, "%s: string %s\n", name, entry->data.string_data.string); break; - case GST_PROPS_INT_RANGE_ID: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: int range %d-%d", name, entry->data.int_range_data.min, + case GST_PROPS_INT_RANGE_TYPE: + GST_DEBUG (GST_CAT_PROPERTIES, "%s: int range %d-%d\n", name, entry->data.int_range_data.min, entry->data.int_range_data.max); break; - case GST_PROPS_FLOAT_RANGE_ID: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: float range %f-%f", name, entry->data.float_range_data.min, + case GST_PROPS_FLOAT_RANGE_TYPE: + GST_DEBUG (GST_CAT_PROPERTIES, "%s: float range %f-%f\n", name, entry->data.float_range_data.min, entry->data.float_range_data.max); break; - case GST_PROPS_LIST_ID: - GST_DEBUG (GST_CAT_PROPERTIES, "[list]"); + case GST_PROPS_LIST_TYPE: + GST_DEBUG (GST_CAT_PROPERTIES, "[list]\n"); { GList *entries = entry->data.list_data.entries; @@ -122,30 +159,30 @@ props_find_func (gconstpointer a, */ #define GST_PROPS_ENTRY_FILL(entry, var_args) \ G_STMT_START { \ - entry->propstype = va_arg (var_args, GstPropsId); \ + entry->propstype = va_arg (var_args, GstPropsType); \ \ switch (entry->propstype) { \ - case GST_PROPS_INT_ID: \ + case GST_PROPS_INT_TYPE: \ entry->data.int_data = va_arg (var_args, gint); \ break; \ - case GST_PROPS_INT_RANGE_ID: \ + case GST_PROPS_INT_RANGE_TYPE: \ entry->data.int_range_data.min = va_arg (var_args, gint); \ entry->data.int_range_data.max = va_arg (var_args, gint); \ break; \ - case GST_PROPS_FLOAT_ID: \ + case GST_PROPS_FLOAT_TYPE: \ entry->data.float_data = va_arg (var_args, gdouble); \ break; \ - case GST_PROPS_FLOAT_RANGE_ID: \ + case GST_PROPS_FLOAT_RANGE_TYPE: \ entry->data.float_range_data.min = va_arg (var_args, gdouble); \ entry->data.float_range_data.max = va_arg (var_args, gdouble); \ break; \ - case GST_PROPS_FOURCC_ID: \ + case GST_PROPS_FOURCC_TYPE: \ entry->data.fourcc_data = va_arg (var_args, gulong); \ break; \ - case GST_PROPS_BOOL_ID: \ + case GST_PROPS_BOOL_TYPE: \ entry->data.bool_data = va_arg (var_args, gboolean); \ break; \ - case GST_PROPS_STRING_ID: \ + case GST_PROPS_STRING_TYPE: \ entry->data.string_data.string = g_strdup (va_arg (var_args, gchar*)); \ break; \ default: \ @@ -153,6 +190,52 @@ G_STMT_START { \ } \ } G_STMT_END + +#define GST_PROPS_ENTRY_READ(entry, var_args, safe, result) \ +G_STMT_START { \ + *result = TRUE; \ + \ + if (safe) { \ + GstPropsType propstype = va_arg (var_args, GstPropsType); \ + if (propstype != entry->propstype) { \ + *result = FALSE; \ + } \ + } \ + if (*result) { \ + switch (entry->propstype) { \ + case GST_PROPS_INT_TYPE: \ + *(va_arg (var_args, gint*)) = entry->data.int_data; \ + break; \ + case GST_PROPS_INT_RANGE_TYPE: \ + *(va_arg (var_args, gint*)) = entry->data.int_range_data.min; \ + *(va_arg (var_args, gint*)) = entry->data.int_range_data.max; \ + break; \ + case GST_PROPS_FLOAT_TYPE: \ + *(va_arg (var_args, gfloat*)) = entry->data.float_data; \ + break; \ + case GST_PROPS_FLOAT_RANGE_TYPE: \ + *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.min; \ + *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.max; \ + break; \ + case GST_PROPS_FOURCC_TYPE: \ + *(va_arg (var_args, guint32*)) = entry->data.fourcc_data; \ + break; \ + case GST_PROPS_BOOL_TYPE: \ + *(va_arg (var_args, gboolean*)) = entry->data.bool_data; \ + break; \ + case GST_PROPS_STRING_TYPE: \ + *(va_arg (var_args, gchar**)) = entry->data.string_data.string; \ + break; \ + case GST_PROPS_LIST_TYPE: \ + *(va_arg (var_args, GList**)) = entry->data.list_data.entries; \ + break; \ + default: \ + *result = FALSE; \ + break; \ + } \ + } \ +} G_STMT_END + static GstPropsEntry* gst_props_alloc_entry (void) { @@ -169,10 +252,10 @@ static void gst_props_entry_destroy (GstPropsEntry *entry) { switch (entry->propstype) { - case GST_PROPS_STRING_ID: + case GST_PROPS_STRING_TYPE: g_free (entry->data.string_data.string); break; - case GST_PROPS_LIST_ID: + case GST_PROPS_LIST_TYPE: { GList *entries = entry->data.list_data.entries; @@ -275,7 +358,7 @@ gst_props_merge_int_entries(GstPropsEntry * newentry, GstPropsEntry * oldentry) gint new_min, new_max, old_min, old_max; gboolean can_merge = FALSE; - if (newentry->propstype == GST_PROPS_INT_ID) { + if (newentry->propstype == GST_PROPS_INT_TYPE) { new_min = newentry->data.int_data; new_max = newentry->data.int_data; } else { @@ -283,7 +366,7 @@ gst_props_merge_int_entries(GstPropsEntry * newentry, GstPropsEntry * oldentry) new_max = newentry->data.int_range_data.max; } - if (oldentry->propstype == GST_PROPS_INT_ID) { + if (oldentry->propstype == GST_PROPS_INT_TYPE) { old_min = oldentry->data.int_data; old_max = oldentry->data.int_data; } else { @@ -312,10 +395,10 @@ gst_props_merge_int_entries(GstPropsEntry * newentry, GstPropsEntry * oldentry) if (can_merge) { if (new_min == new_max) { - newentry->propstype = GST_PROPS_INT_ID; + newentry->propstype = GST_PROPS_INT_TYPE; newentry->data.int_data = new_min; } else { - newentry->propstype = GST_PROPS_INT_RANGE_ID; + newentry->propstype = GST_PROPS_INT_RANGE_TYPE; newentry->data.int_range_data.min = new_min; newentry->data.int_range_data.max = new_max; } @@ -411,27 +494,27 @@ gst_props_newv (const gchar *firstname, va_list var_args) GST_PROPS_ENTRY_FILL (entry, var_args); switch (entry->propstype) { - case GST_PROPS_INT_ID: - case GST_PROPS_INT_RANGE_ID: + case GST_PROPS_INT_TYPE: + case GST_PROPS_INT_RANGE_TYPE: entry_type = GST_PROPS_LIST_T_INTS; break; - case GST_PROPS_FLOAT_ID: - case GST_PROPS_FLOAT_RANGE_ID: + case GST_PROPS_FLOAT_TYPE: + case GST_PROPS_FLOAT_RANGE_TYPE: entry_type = GST_PROPS_LIST_T_FLOATS; break; - case GST_PROPS_FOURCC_ID: - case GST_PROPS_BOOL_ID: - case GST_PROPS_STRING_ID: + case GST_PROPS_FOURCC_TYPE: + case GST_PROPS_BOOL_TYPE: + case GST_PROPS_STRING_TYPE: entry_type = GST_PROPS_LIST_T_MISC; break; - case GST_PROPS_LIST_ID: + case GST_PROPS_LIST_TYPE: g_return_val_if_fail (inlist == FALSE, NULL); inlist = TRUE; list_entry = entry; list_type = GST_PROPS_LIST_T_UNSET; list_entry->data.list_data.entries = NULL; break; - case GST_PROPS_END_ID: + case GST_PROPS_END_TYPE: g_return_val_if_fail (inlist == TRUE, NULL); /* if list was of size 1, replace the list by a the item it contains */ @@ -605,10 +688,10 @@ gst_props_entry_copy (GstPropsEntry *entry) newentry = gst_props_alloc_entry (); memcpy (newentry, entry, sizeof (GstPropsEntry)); - if (entry->propstype == GST_PROPS_LIST_ID) { + if (entry->propstype == GST_PROPS_LIST_TYPE) { newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries); } - else if (entry->propstype == GST_PROPS_STRING_ID) { + else if (entry->propstype == GST_PROPS_STRING_TYPE) { newentry->data.string_data.string = g_strdup (entry->data.string_data.string); } @@ -679,8 +762,8 @@ gst_props_copy_on_write (GstProps *props) return new; } -static GstPropsEntry* -gst_props_get_entry_func (GstProps *props, const gchar *name) +const GstPropsEntry* +gst_props_get_entry (GstProps *props, const gchar *name) { GList *lentry; GQuark quark; @@ -703,134 +786,168 @@ gst_props_get_entry_func (GstProps *props, const gchar *name) gboolean gst_props_has_property (GstProps *props, const gchar *name) { - return (gst_props_get_entry_func (props, name) != NULL); + return (gst_props_get_entry (props, name) != NULL); } -/** - * gst_props_get_int: - * @props: the props to get the int value from - * @name: the name of the props entry to get. - * - * Get the named entry as an integer. - * - * Returns: the integer value of the named entry, 0 if not found. - */ -gint -gst_props_get_int (GstProps *props, const gchar *name) +gboolean +gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type) { - GstPropsEntry *thisentry; + const GstPropsEntry *entry; - thisentry = gst_props_get_entry_func (props, name); + entry = gst_props_get_entry (props, name); + if (!entry) + return FALSE; - if (thisentry) { - return thisentry->data.int_data; - } - else { - g_warning ("props: property %s not found", name); - } - return 0; + return (entry->propstype == type); } -/** - * gst_props_get_float: - * @props: the props to get the float value from - * @name: the name of the props entry to get. - * - * Get the named entry as a float. - * - * Returns: the float value of the named entry, 0.0 if not found. - */ -gfloat -gst_props_get_float (GstProps *props, const gchar *name) +gboolean +gst_props_has_fixed_property (GstProps *props, const gchar *name) { - GstPropsEntry *thisentry; + const GstPropsEntry *entry; - thisentry = gst_props_get_entry_func (props, name); + entry = gst_props_get_entry (props, name); + if (!entry) + return FALSE; - if (thisentry) { - return thisentry->data.float_data; - } - else { - g_warning ("props: property %s not found", name); - } - return 0.0F; + return !GST_PROPS_ENTRY_IS_VARIABLE (entry); } -/** - * gst_props_get_fourcc_int: - * @props: the props to get the fourcc value from - * @name: the name of the props entry to get. - * - * Get the named entry as a gulong fourcc. - * - * Returns: the fourcc value of the named entry, 0 if not found. - */ -gulong -gst_props_get_fourcc_int (GstProps *props, const gchar *name) +GstPropsType +gst_props_entry_get_type (const GstPropsEntry *entry) { - GstPropsEntry *thisentry; + g_return_val_if_fail (entry != NULL, GST_PROPS_INVALID_TYPE); - thisentry = gst_props_get_entry_func (props, name); + return entry->propstype; +} - if (thisentry) { - return thisentry->data.fourcc_data; - } - else { - g_warning ("props: property %s not found", name); - } - return 0; +const gchar* +gst_props_entry_get_name (const GstPropsEntry *entry) +{ + g_return_val_if_fail (entry != NULL, NULL); + + return g_quark_to_string (entry->propid); } -/** - * gst_props_get_boolean: - * @props: the props to get the fourcc value from - * @name: the name of the props entry to get. - * - * Get the named entry as a boolean value. - * - * Returns: the boolean value of the named entry, 0 if not found. - */ gboolean -gst_props_get_boolean (GstProps *props, const gchar *name) +gst_props_entry_is_fixed (const GstPropsEntry *entry) +{ + g_return_val_if_fail (entry != NULL, FALSE); + + return !GST_PROPS_ENTRY_IS_VARIABLE (entry); +} + +static gboolean +gst_props_entry_getv (const GstPropsEntry *entry, gboolean safe, va_list var_args) { - GstPropsEntry *thisentry; + gboolean result; - thisentry = gst_props_get_entry_func (props, name); + GST_PROPS_ENTRY_READ (entry, var_args, safe, &result); - if (thisentry) { - return thisentry->data.bool_data; - } - else { - g_warning ("props: property %s not found", name); - } - return 0; + return result; } -/** - * gst_props_get_string: - * @props: the props to get the fourcc value from - * @name: the name of the props entry to get. - * - * Get the named entry as a string value. - * - * Returns: the string value of the named entry, NULL if not found. - */ -const gchar* -gst_props_get_string (GstProps *props, const gchar *name) +gboolean +gst_props_entry_get (const GstPropsEntry *entry, ...) +{ + gboolean result; + va_list var_args; + + g_return_val_if_fail (entry != NULL, FALSE); + + va_start (var_args, entry); + result = gst_props_entry_getv (entry, FALSE, var_args); + va_end (var_args); + + return result; +} + +static gboolean +gst_props_entry_get_safe (const GstPropsEntry *entry, ...) { - GstPropsEntry *thisentry; + gboolean result; + va_list var_args; - thisentry = gst_props_get_entry_func (props, name); + g_return_val_if_fail (entry != NULL, FALSE); - if (thisentry) { - return thisentry->data.string_data.string; - } - else { - g_warning ("props: property %s not found", name); + va_start (var_args, entry); + result = gst_props_entry_getv (entry, TRUE, var_args); + va_end (var_args); + + return result; +} + +gboolean +gst_props_get (GstProps *props, gchar *first_name, ...) +{ + va_list var_args; + + va_start (var_args, first_name); + + while (first_name) { + const GstPropsEntry *entry = gst_props_get_entry (props, first_name); + gboolean result; + + if (!entry) return FALSE; + GST_PROPS_ENTRY_READ (entry, var_args, FALSE, &result); + if (!result) return FALSE; + + first_name = va_arg (var_args, gchar *); } - return NULL; + va_end (var_args); + + return TRUE; +} + +gboolean +gst_props_entry_get_int (const GstPropsEntry *entry, gint *val) +{ + return gst_props_entry_get_safe (entry, GST_PROPS_INT_TYPE, val); +} + +gboolean +gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val) +{ + return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_TYPE, val); +} + +gboolean +gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val) +{ + return gst_props_entry_get_safe (entry, GST_PROPS_FOURCC_TYPE, val); +} + +gboolean +gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val) +{ + return gst_props_entry_get_safe (entry, GST_PROPS_BOOL_TYPE, val); +} + +gboolean +gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val) +{ + return gst_props_entry_get_safe (entry, GST_PROPS_STRING_TYPE, val); +} + +gboolean +gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max) +{ + return gst_props_entry_get_safe (entry, GST_PROPS_INT_RANGE_TYPE, min, max); } +gboolean +gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max) +{ + return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_RANGE_TYPE, min, max); +} + +gboolean +gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val) +{ + return gst_props_entry_get_safe (entry, GST_PROPS_LIST_TYPE, val); +} + + /** * gst_props_merge: * @props: the property to merge into @@ -887,12 +1004,12 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s", g_quark_to_string (entry1->propid), g_quark_to_string (entry2->propid)); - if (entry2->propstype == GST_PROPS_LIST_ID && entry1->propstype != GST_PROPS_LIST_ID) { + if (entry2->propstype == GST_PROPS_LIST_TYPE && entry1->propstype != GST_PROPS_LIST_TYPE) { return gst_props_entry_check_list_compatibility (entry1, entry2); } switch (entry1->propstype) { - case GST_PROPS_LIST_ID: + case GST_PROPS_LIST_TYPE: { GList *entrylist = entry1->data.list_data.entries; gboolean valid = TRUE; /* innocent until proven guilty */ @@ -907,79 +1024,79 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry return valid; } - case GST_PROPS_INT_RANGE_ID: + case GST_PROPS_INT_RANGE_TYPE: switch (entry2->propstype) { /* a - b <---> a - c */ - case GST_PROPS_INT_RANGE_ID: + case GST_PROPS_INT_RANGE_TYPE: return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min && entry2->data.int_range_data.max >= entry1->data.int_range_data.max); default: break; } break; - case GST_PROPS_FLOAT_RANGE_ID: + case GST_PROPS_FLOAT_RANGE_TYPE: switch (entry2->propstype) { /* a - b <---> a - c */ - case GST_PROPS_FLOAT_RANGE_ID: + case GST_PROPS_FLOAT_RANGE_TYPE: return (entry2->data.float_range_data.min <= entry1->data.float_range_data.min && entry2->data.float_range_data.max >= entry1->data.float_range_data.max); default: break; } break; - case GST_PROPS_FOURCC_ID: + case GST_PROPS_FOURCC_TYPE: switch (entry2->propstype) { /* b <---> a */ - case GST_PROPS_FOURCC_ID: - GST_DEBUG(GST_CAT_PROPERTIES,"\"%4.4s\" <--> \"%4.4s\" ?", + case GST_PROPS_FOURCC_TYPE: + GST_DEBUG(GST_CAT_PROPERTIES,"\"%4.4s\" <--> \"%4.4s\" ?\n", (char*) &entry2->data.fourcc_data, (char*) &entry1->data.fourcc_data); return (entry2->data.fourcc_data == entry1->data.fourcc_data); default: break; } break; - case GST_PROPS_INT_ID: + case GST_PROPS_INT_TYPE: switch (entry2->propstype) { /* b <---> a - d */ - case GST_PROPS_INT_RANGE_ID: - GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?",entry2->data.int_range_data.min, + case GST_PROPS_INT_RANGE_TYPE: + GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?\n",entry2->data.int_range_data.min, entry1->data.int_data,entry2->data.int_range_data.max); return (entry2->data.int_range_data.min <= entry1->data.int_data && entry2->data.int_range_data.max >= entry1->data.int_data); /* b <---> a */ - case GST_PROPS_INT_ID: - GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?",entry1->data.int_data,entry2->data.int_data); + case GST_PROPS_INT_TYPE: + GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?\n",entry1->data.int_data,entry2->data.int_data); return (entry2->data.int_data == entry1->data.int_data); default: break; } break; - case GST_PROPS_FLOAT_ID: + case GST_PROPS_FLOAT_TYPE: switch (entry2->propstype) { /* b <---> a - d */ - case GST_PROPS_FLOAT_RANGE_ID: + case GST_PROPS_FLOAT_RANGE_TYPE: return (entry2->data.float_range_data.min <= entry1->data.float_data && entry2->data.float_range_data.max >= entry1->data.float_data); /* b <---> a */ - case GST_PROPS_FLOAT_ID: + case GST_PROPS_FLOAT_TYPE: return (entry2->data.float_data == entry1->data.float_data); default: break; } break; - case GST_PROPS_BOOL_ID: + case GST_PROPS_BOOL_TYPE: switch (entry2->propstype) { /* t <---> t */ - case GST_PROPS_BOOL_ID: + case GST_PROPS_BOOL_TYPE: return (entry2->data.bool_data == entry1->data.bool_data); default: break; } - case GST_PROPS_STRING_ID: + case GST_PROPS_STRING_TYPE: switch (entry2->propstype) { /* t <---> t */ - case GST_PROPS_STRING_ID: - GST_DEBUG(GST_CAT_PROPERTIES,"\"%s\" <--> \"%s\" ?", + case GST_PROPS_STRING_TYPE: + GST_DEBUG(GST_CAT_PROPERTIES,"\"%s\" <--> \"%s\" ?\n", entry2->data.string_data.string, entry1->data.string_data.string); return (!strcmp (entry2->data.string_data.string, entry1->data.string_data.string)); default: @@ -1065,9 +1182,9 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) /* try to move the ranges and lists first */ switch (entry2->propstype) { - case GST_PROPS_INT_RANGE_ID: - case GST_PROPS_FLOAT_RANGE_ID: - case GST_PROPS_LIST_ID: + case GST_PROPS_INT_RANGE_TYPE: + case GST_PROPS_FLOAT_RANGE_TYPE: + case GST_PROPS_LIST_TYPE: { GstPropsEntry *temp; @@ -1080,7 +1197,7 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) } switch (entry1->propstype) { - case GST_PROPS_LIST_ID: + case GST_PROPS_LIST_TYPE: { GList *entrylist = entry1->data.list_data.entries; GList *intersection = NULL; @@ -1092,7 +1209,7 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) intersectentry = gst_props_entry_intersect (entry2, entry); if (intersectentry) { - if (intersectentry->propstype == GST_PROPS_LIST_ID) { + if (intersectentry->propstype == GST_PROPS_LIST_TYPE) { intersection = g_list_concat (intersection, intersectentry->data.list_data.entries); /* set the list to NULL because the entries are concatenated to the above * list and we don't want to free them */ @@ -1115,16 +1232,16 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) else { result = gst_props_alloc_entry (); result->propid = entry1->propid; - result->propstype = GST_PROPS_LIST_ID; + result->propstype = GST_PROPS_LIST_TYPE; result->data.list_data.entries = g_list_reverse (intersection); } } return result; } - case GST_PROPS_INT_RANGE_ID: + case GST_PROPS_INT_RANGE_TYPE: switch (entry2->propstype) { /* a - b <---> a - c */ - case GST_PROPS_INT_RANGE_ID: + case GST_PROPS_INT_RANGE_TYPE: { gint lower = MAX (entry1->data.int_range_data.min, entry2->data.int_range_data.min); gint upper = MIN (entry1->data.int_range_data.max, entry2->data.int_range_data.max); @@ -1134,27 +1251,27 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) result->propid = entry1->propid; if (lower == upper) { - result->propstype = GST_PROPS_INT_ID; + result->propstype = GST_PROPS_INT_TYPE; result->data.int_data = lower; } else { - result->propstype = GST_PROPS_INT_RANGE_ID; + result->propstype = GST_PROPS_INT_RANGE_TYPE; result->data.int_range_data.min = lower; result->data.int_range_data.max = upper; } } break; } - case GST_PROPS_LIST_ID: + case GST_PROPS_LIST_TYPE: { GList *entries = entry2->data.list_data.entries; result = gst_props_alloc_entry (); result->propid = entry1->propid; - result->propstype = GST_PROPS_LIST_ID; + result->propstype = GST_PROPS_LIST_TYPE; result->data.list_data.entries = NULL; while (entries) { GstPropsEntry * this = (GstPropsEntry *)entries->data; - if (this->propstype != GST_PROPS_INT_ID) { + if (this->propstype != GST_PROPS_INT_TYPE) { /* no hope, this list doesn't even contain ints! */ gst_props_entry_destroy (result); result = NULL; @@ -1169,7 +1286,7 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) } break; } - case GST_PROPS_INT_ID: + case GST_PROPS_INT_TYPE: { if (entry1->data.int_range_data.min <= entry2->data.int_data && entry1->data.int_range_data.max >= entry2->data.int_data) { @@ -1181,10 +1298,10 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) break; } break; - case GST_PROPS_FLOAT_RANGE_ID: + case GST_PROPS_FLOAT_RANGE_TYPE: switch (entry2->propstype) { /* a - b <---> a - c */ - case GST_PROPS_FLOAT_RANGE_ID: + case GST_PROPS_FLOAT_RANGE_TYPE: { gfloat lower = MAX (entry1->data.float_range_data.min, entry2->data.float_range_data.min); gfloat upper = MIN (entry1->data.float_range_data.max, entry2->data.float_range_data.max); @@ -1194,18 +1311,18 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) result->propid = entry1->propid; if (lower == upper) { - result->propstype = GST_PROPS_FLOAT_ID; + result->propstype = GST_PROPS_FLOAT_TYPE; result->data.float_data = lower; } else { - result->propstype = GST_PROPS_FLOAT_RANGE_ID; + result->propstype = GST_PROPS_FLOAT_RANGE_TYPE; result->data.float_range_data.min = lower; result->data.float_range_data.max = upper; } } break; } - case GST_PROPS_FLOAT_ID: + case GST_PROPS_FLOAT_TYPE: if (entry1->data.float_range_data.min <= entry2->data.float_data && entry1->data.float_range_data.max >= entry2->data.float_data) { result = gst_props_entry_copy (entry2); @@ -1214,49 +1331,49 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) break; } break; - case GST_PROPS_FOURCC_ID: + case GST_PROPS_FOURCC_TYPE: switch (entry2->propstype) { /* b <---> a */ - case GST_PROPS_FOURCC_ID: + case GST_PROPS_FOURCC_TYPE: if (entry1->data.fourcc_data == entry2->data.fourcc_data) result = gst_props_entry_copy (entry1); default: break; } break; - case GST_PROPS_INT_ID: + case GST_PROPS_INT_TYPE: switch (entry2->propstype) { /* b <---> a */ - case GST_PROPS_INT_ID: + case GST_PROPS_INT_TYPE: if (entry1->data.int_data == entry2->data.int_data) result = gst_props_entry_copy (entry1); default: break; } break; - case GST_PROPS_FLOAT_ID: + case GST_PROPS_FLOAT_TYPE: switch (entry2->propstype) { /* b <---> a */ - case GST_PROPS_FLOAT_ID: + case GST_PROPS_FLOAT_TYPE: if (entry1->data.float_data == entry2->data.float_data) result = gst_props_entry_copy (entry1); default: break; } break; - case GST_PROPS_BOOL_ID: + case GST_PROPS_BOOL_TYPE: switch (entry2->propstype) { /* t <---> t */ - case GST_PROPS_BOOL_ID: + case GST_PROPS_BOOL_TYPE: if (entry1->data.bool_data == entry2->data.bool_data) result = gst_props_entry_copy (entry1); default: break; } - case GST_PROPS_STRING_ID: + case GST_PROPS_STRING_TYPE: switch (entry2->propstype) { /* t <---> t */ - case GST_PROPS_STRING_ID: + case GST_PROPS_STRING_TYPE: if (!strcmp (entry1->data.string_data.string, entry2->data.string_data.string)) result = gst_props_entry_copy (entry1); default: @@ -1392,7 +1509,7 @@ gst_props_normalize (GstProps *props) while (entries) { GstPropsEntry *entry = (GstPropsEntry *) entries->data; - if (entry->propstype == GST_PROPS_LIST_ID) { + if (entry->propstype == GST_PROPS_LIST_TYPE) { GList *list_entries = entry->data.list_data.entries; while (list_entries) { @@ -1443,14 +1560,14 @@ gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent) gchar *str; switch (entry->propstype) { - case GST_PROPS_INT_ID: + case GST_PROPS_INT_TYPE: subtree = xmlNewChild (parent, NULL, "int", NULL); xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); str = g_strdup_printf ("%d", entry->data.int_data); xmlNewProp (subtree, "value", str); g_free(str); break; - case GST_PROPS_INT_RANGE_ID: + case GST_PROPS_INT_RANGE_TYPE: subtree = xmlNewChild (parent, NULL, "range", NULL); xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); str = g_strdup_printf ("%d", entry->data.int_range_data.min); @@ -1460,14 +1577,14 @@ gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent) xmlNewProp (subtree, "max", str); g_free(str); break; - case GST_PROPS_FLOAT_ID: + case GST_PROPS_FLOAT_TYPE: subtree = xmlNewChild (parent, NULL, "float", NULL); xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); str = g_strdup_printf ("%f", entry->data.float_data); xmlNewProp (subtree, "value", str); g_free(str); break; - case GST_PROPS_FLOAT_RANGE_ID: + case GST_PROPS_FLOAT_RANGE_TYPE: subtree = xmlNewChild (parent, NULL, "floatrange", NULL); xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); str = g_strdup_printf ("%f", entry->data.float_range_data.min); @@ -1477,7 +1594,7 @@ gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent) xmlNewProp (subtree, "max", str); g_free(str); break; - case GST_PROPS_FOURCC_ID: + case GST_PROPS_FOURCC_TYPE: str = g_strdup_printf ("%4.4s", (gchar *)&entry->data.fourcc_data); xmlAddChild (parent, xmlNewComment (str)); g_free(str); @@ -1487,12 +1604,12 @@ gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent) xmlNewProp (subtree, "hexvalue", str); g_free(str); break; - case GST_PROPS_BOOL_ID: + case GST_PROPS_BOOL_TYPE: subtree = xmlNewChild (parent, NULL, "boolean", NULL); xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); xmlNewProp (subtree, "value", (entry->data.bool_data ? "true" : "false")); break; - case GST_PROPS_STRING_ID: + case GST_PROPS_STRING_TYPE: subtree = xmlNewChild (parent, NULL, "string", NULL); xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); xmlNewProp (subtree, "value", entry->data.string_data.string); @@ -1528,7 +1645,7 @@ gst_props_save_thyself (GstProps *props, xmlNodePtr parent) GstPropsEntry *entry = (GstPropsEntry *) proplist->data; switch (entry->propstype) { - case GST_PROPS_LIST_ID: + case GST_PROPS_LIST_TYPE: subtree = xmlNewChild (parent, NULL, "list", NULL); xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree); @@ -1552,7 +1669,7 @@ gst_props_load_thyself_func (xmlNodePtr field) entry = gst_props_alloc_entry (); if (!strcmp(field->name, "int")) { - entry->propstype = GST_PROPS_INT_ID; + entry->propstype = GST_PROPS_INT_TYPE; prop = xmlGetProp(field, "name"); entry->propid = g_quark_from_string (prop); g_free (prop); @@ -1561,7 +1678,7 @@ gst_props_load_thyself_func (xmlNodePtr field) g_free (prop); } else if (!strcmp(field->name, "range")) { - entry->propstype = GST_PROPS_INT_RANGE_ID; + entry->propstype = GST_PROPS_INT_RANGE_TYPE; prop = xmlGetProp(field, "name"); entry->propid = g_quark_from_string (prop); g_free (prop); @@ -1573,7 +1690,7 @@ gst_props_load_thyself_func (xmlNodePtr field) g_free (prop); } else if (!strcmp(field->name, "float")) { - entry->propstype = GST_PROPS_FLOAT_ID; + entry->propstype = GST_PROPS_FLOAT_TYPE; prop = xmlGetProp(field, "name"); entry->propid = g_quark_from_string (prop); g_free (prop); @@ -1582,7 +1699,7 @@ gst_props_load_thyself_func (xmlNodePtr field) g_free (prop); } else if (!strcmp(field->name, "floatrange")) { - entry->propstype = GST_PROPS_FLOAT_RANGE_ID; + entry->propstype = GST_PROPS_FLOAT_RANGE_TYPE; prop = xmlGetProp(field, "name"); entry->propid = g_quark_from_string (prop); g_free (prop); @@ -1594,7 +1711,7 @@ gst_props_load_thyself_func (xmlNodePtr field) g_free (prop); } else if (!strcmp(field->name, "boolean")) { - entry->propstype = GST_PROPS_BOOL_ID; + entry->propstype = GST_PROPS_BOOL_TYPE; prop = xmlGetProp(field, "name"); entry->propid = g_quark_from_string (prop); g_free (prop); @@ -1604,7 +1721,7 @@ gst_props_load_thyself_func (xmlNodePtr field) g_free (prop); } else if (!strcmp(field->name, "fourcc")) { - entry->propstype = GST_PROPS_FOURCC_ID; + entry->propstype = GST_PROPS_FOURCC_TYPE; prop = xmlGetProp(field, "name"); entry->propid = g_quark_from_string (prop); g_free (prop); @@ -1613,7 +1730,7 @@ gst_props_load_thyself_func (xmlNodePtr field) g_free (prop); } else if (!strcmp(field->name, "string")) { - entry->propstype = GST_PROPS_STRING_ID; + entry->propstype = GST_PROPS_STRING_TYPE; prop = xmlGetProp(field, "name"); entry->propid = g_quark_from_string (prop); g_free (prop); @@ -1655,7 +1772,7 @@ gst_props_load_thyself (xmlNodePtr parent) prop = xmlGetProp (field, "name"); entry->propid = g_quark_from_string (prop); g_free (prop); - entry->propstype = GST_PROPS_LIST_ID; + entry->propstype = GST_PROPS_LIST_TYPE; entry->data.list_data.entries = NULL; while (subfield) { diff --git a/gst/gstprops.h b/gst/gstprops.h index ab63efa..9343927 100644 --- a/gst/gstprops.h +++ b/gst/gstprops.h @@ -26,86 +26,110 @@ #include -#include +#include typedef struct _GstProps GstProps; +extern GType _gst_props_type; + +#define GST_TYPE_PROPS (_get_props_type) typedef enum { - GST_PROPS_END_ID = 0, - GST_PROPS_INT_ID, - GST_PROPS_FLOAT_ID, - GST_PROPS_FOURCC_ID, - GST_PROPS_BOOL_ID, - GST_PROPS_STRING_ID, + GST_PROPS_END_TYPE = 0, + + GST_PROPS_INVALID_TYPE, + + GST_PROPS_INT_TYPE, + GST_PROPS_FLOAT_TYPE, + GST_PROPS_FOURCC_TYPE, + GST_PROPS_BOOL_TYPE, + GST_PROPS_STRING_TYPE, - GST_PROPS_VAR_ID, /* after this marker start the variable properties */ + GST_PROPS_VAR_TYPE, /* after this marker start the variable properties */ - GST_PROPS_LIST_ID, - GST_PROPS_FLOAT_RANGE_ID, - GST_PROPS_INT_RANGE_ID, + GST_PROPS_LIST_TYPE, + GST_PROPS_FLOAT_RANGE_TYPE, + GST_PROPS_INT_RANGE_TYPE, - GST_PROPS_LAST_ID = GST_PROPS_END_ID + 16, -} GstPropsId; + GST_PROPS_LAST_TYPE = GST_PROPS_END_TYPE + 16, +} GstPropsType; #define GST_MAKE_FOURCC(a,b,c,d) ((a)|(b)<<8|(c)<<16|(d)<<24) #define GST_STR_FOURCC(f) (((f)[0])|((f)[1]<<8)|((f)[2]<<16)|((f)[3]<<24)) -#define GST_PROPS_LIST(a...) GST_PROPS_LIST_ID,##a,NULL -#define GST_PROPS_INT(a) GST_PROPS_INT_ID,(a) -#define GST_PROPS_INT_RANGE(a,b) GST_PROPS_INT_RANGE_ID,(a),(b) -#define GST_PROPS_FLOAT(a) GST_PROPS_FLOAT_ID,(a) -#define GST_PROPS_FLOAT_RANGE(a,b) GST_PROPS_FLOAT_RANGE_ID,(a),(b) -#define GST_PROPS_FOURCC(a) GST_PROPS_FOURCC_ID,(a) -#define GST_PROPS_BOOLEAN(a) GST_PROPS_BOOL_ID,(a) -#define GST_PROPS_STRING(a) GST_PROPS_STRING_ID,(a) +#define GST_PROPS_LIST(a...) GST_PROPS_LIST_TYPE,##a,NULL +#define GST_PROPS_INT(a) GST_PROPS_INT_TYPE,(a) +#define GST_PROPS_INT_RANGE(a,b) GST_PROPS_INT_RANGE_TYPE,(a),(b) +#define GST_PROPS_FLOAT(a) GST_PROPS_FLOAT_TYPE,(a) +#define GST_PROPS_FLOAT_RANGE(a,b) GST_PROPS_FLOAT_RANGE_TYPE,(a),(b) +#define GST_PROPS_FOURCC(a) GST_PROPS_FOURCC_TYPE,(a) +#define GST_PROPS_BOOLEAN(a) GST_PROPS_BOOL_TYPE,(a) +#define GST_PROPS_STRING(a) GST_PROPS_STRING_TYPE,(a) #define GST_PROPS_INT_POSITIVE GST_PROPS_INT_RANGE(0,G_MAXINT) #define GST_PROPS_INT_NEGATIVE GST_PROPS_INT_RANGE(G_MININT,0) #define GST_PROPS_INT_ANY GST_PROPS_INT_RANGE(G_MININT,G_MAXINT) +typedef struct _GstPropsEntry GstPropsEntry; struct _GstProps { gint refcount; - GMutex *lock; gboolean fixed; GList *properties; /* real properties for this property */ }; /* initialize the subsystem */ -void _gst_props_initialize (void); +void _gst_props_initialize (void); + +GstProps* gst_props_new (const gchar *firstname, ...); +GstProps* gst_props_newv (const gchar *firstname, va_list var_args); + +void gst_props_unref (GstProps *props); +void gst_props_ref (GstProps *props); +void gst_props_destroy (GstProps *props); -GstProps* gst_props_new (const gchar *firstname, ...); -GstProps* gst_props_newv (const gchar *firstname, va_list var_args); +void gst_props_debug (GstProps *props); -void gst_props_unref (GstProps *props); -void gst_props_ref (GstProps *props); -void gst_props_destroy (GstProps *props); +GstProps* gst_props_copy (GstProps *props); +GstProps* gst_props_copy_on_write (GstProps *props); -void gst_props_debug (GstProps *props); +GstProps* gst_props_merge (GstProps *props, GstProps *tomerge); -GstProps* gst_props_copy (GstProps *props); -GstProps* gst_props_copy_on_write (GstProps *props); +gboolean gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops); +GstProps* gst_props_intersect (GstProps *props1, GstProps *props2); +GList* gst_props_normalize (GstProps *props); -GstProps* gst_props_merge (GstProps *props, GstProps *tomerge); +GstProps* gst_props_set (GstProps *props, const gchar *name, ...); +gboolean gst_props_get (GstProps *props, gchar *first_name, ...); -gboolean gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops); -GstProps* gst_props_intersect (GstProps *props1, GstProps *props2); -GList* gst_props_normalize (GstProps *props); +gboolean gst_props_has_property (GstProps *props, const gchar *name); +gboolean gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type); +gboolean gst_props_has_fixed_property (GstProps *props, const gchar *name); -GstProps* gst_props_set (GstProps *props, const gchar *name, ...); -gboolean gst_props_has_property (GstProps *props, const gchar *name); +/* working with props entries */ +const GstPropsEntry* gst_props_get_entry (GstProps *props, const gchar *name); +GstPropsType gst_props_entry_get_type (const GstPropsEntry *entry); +const gchar* gst_props_entry_get_name (const GstPropsEntry *entry); +gboolean gst_props_entry_is_fixed (const GstPropsEntry *entry); + +gboolean gst_props_entry_get (const GstPropsEntry *props, ...); + +gboolean gst_props_entry_get_int (const GstPropsEntry *entry, gint *val); +gboolean gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val); +gboolean gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val); +gboolean gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val); +gboolean gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val); +gboolean gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max); +gboolean gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max); +gboolean gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val); -gint gst_props_get_int (GstProps *props, const gchar *name); -gfloat gst_props_get_float (GstProps *props, const gchar *name); -gulong gst_props_get_fourcc_int (GstProps *props, const gchar *name); -gboolean gst_props_get_boolean (GstProps *props, const gchar *name); -const gchar* gst_props_get_string (GstProps *props, const gchar *name); #ifndef GST_DISABLE_LOADSAVE -xmlNodePtr gst_props_save_thyself (GstProps *props, xmlNodePtr parent); -GstProps* gst_props_load_thyself (xmlNodePtr parent); +xmlNodePtr gst_props_save_thyself (GstProps *props, xmlNodePtr parent); +GstProps* gst_props_load_thyself (xmlNodePtr parent); #endif + + #endif /* __GST_PROPS_H__ */ diff --git a/gst/gstpropsprivate.h b/gst/gstpropsprivate.h deleted file mode 100644 index b7c4512..0000000 --- a/gst/gstpropsprivate.h +++ /dev/null @@ -1,62 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * - * gstpropsprivate.h: Private header for properties subsystem - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - - -#ifndef __GST_PROPS_PRIV_H__ -#define __GST_PROPS_PRIV_H__ - -#include - -#define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_ID) - -typedef struct _GstPropsEntry GstPropsEntry; - -struct _GstPropsEntry { - GQuark propid; - GstPropsId propstype; - - union { - /* flat values */ - gboolean bool_data; - guint32 fourcc_data; - gint int_data; - gfloat float_data; - - /* structured values */ - struct { - GList *entries; - } list_data; - struct { - gchar *string; - } string_data; - struct { - gint min; - gint max; - } int_range_data; - struct { - gfloat min; - gfloat max; - } float_range_data; - } data; -}; - -#endif /* __GST_PROPS_PRIV_H__ */ diff --git a/gst/gstqueue.c b/gst/gstqueue.c index 3540743..cf8ec85 100644 --- a/gst/gstqueue.c +++ b/gst/gstqueue.c @@ -83,7 +83,6 @@ static GstBuffer * gst_queue_get (GstPad *pad); static GstBufferPool* gst_queue_get_bufferpool (GstPad *pad); static void gst_queue_locked_flush (GstQueue *queue); -static void gst_queue_flush (GstQueue *queue); static GstElementStateReturn gst_queue_change_state (GstElement *element); @@ -275,15 +274,6 @@ gst_queue_locked_flush (GstQueue *queue) } static void -gst_queue_flush (GstQueue *queue) -{ - g_mutex_lock (queue->qlock); - gst_queue_locked_flush (queue); - g_mutex_unlock (queue->qlock); -} - - -static void gst_queue_chain (GstPad *pad, GstBuffer *buf) { GstQueue *queue; @@ -378,7 +368,7 @@ restart: return; } else { - gst_element_info (GST_ELEMENT (queue), "waiting for the app to restart source pad elements"); + g_print ("%s: waiting for the app to restart source pad elements\n", GST_ELEMENT_NAME (queue)); } } @@ -459,7 +449,7 @@ restart: goto restart; } else { - gst_element_info (GST_ELEMENT (queue), "waiting for the app to restart sink pad elements"); + g_print ("%s: waiting for the app to restart source pad elements\n", GST_ELEMENT_NAME (queue)); } } diff --git a/gst/gstscheduler.c b/gst/gstscheduler.c index 9e7b7ff..977f2c2 100644 --- a/gst/gstscheduler.c +++ b/gst/gstscheduler.c @@ -24,6 +24,7 @@ #include "gst_private.h" +#include "gstsystemclock.h" #include "gstscheduler.h" static void gst_scheduler_class_init (GstSchedulerClass *klass); @@ -67,6 +68,13 @@ gst_scheduler_class_init (GstSchedulerClass *klass) static void gst_scheduler_init (GstScheduler *sched) { + sched->clock_providers = NULL; + sched->clock_receivers = NULL; + sched->schedulers = NULL; + sched->state = GST_SCHEDULER_STATE_NONE; + sched->parent = NULL; + sched->parent_sched = NULL; + sched->clock = NULL; } /** @@ -171,11 +179,48 @@ gst_scheduler_add_element (GstScheduler *sched, GstElement *element) g_return_if_fail (GST_IS_SCHEDULER (sched)); g_return_if_fail (GST_IS_ELEMENT (element)); + if (element->getclockfunc) { + sched->clock_providers = g_list_prepend (sched->clock_providers, element); + } + if (element->setclockfunc) { + sched->clock_receivers = g_list_prepend (sched->clock_receivers, element); + } + if (CLASS (sched)->add_element) CLASS (sched)->add_element (sched, element); } /** + * gst_scheduler_remove_element: + * @sched: the schedulerr + * @element: the element to remov + * + * Remove an element from the schedulerr. + */ +void +gst_scheduler_remove_element (GstScheduler *sched, GstElement *element) +{ + GList *pads; + + g_return_if_fail (GST_IS_SCHEDULER (sched)); + g_return_if_fail (GST_IS_ELEMENT (element)); + + sched->clock_providers = g_list_remove (sched->clock_providers, element); + sched->clock_receivers = g_list_remove (sched->clock_receivers, element); + + if (CLASS (sched)->remove_element) + CLASS (sched)->remove_element (sched, element); + + for (pads = element->pads; pads; pads = pads->next) { + GstPad *pad = GST_PAD (pads->data); + + if (GST_IS_REAL_PAD (pad)) { + gst_pad_unset_sched (GST_PAD (pads->data)); + } + } +} + +/** * gst_scheduler_state_transition: * @sched: the scheduler * @element: the element with the state transition @@ -192,39 +237,66 @@ gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint t g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_STATE_FAILURE); g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE); + if (element == sched->parent && sched->parent_sched == NULL) { + + switch (transition) { + case GST_STATE_READY_TO_PAUSED: + { + GstClock *clock = gst_scheduler_get_clock (sched); + + if (clock) + gst_clock_reset (clock); + + sched->current_clock = clock; + break; + } + case GST_STATE_PAUSED_TO_PLAYING: + { + gst_scheduler_set_clock (sched, sched->current_clock); + if (sched->current_clock) + gst_clock_activate (sched->current_clock, TRUE); + break; + } + case GST_STATE_PLAYING_TO_PAUSED: + if (sched->current_clock) + gst_clock_activate (sched->current_clock, FALSE); + break; + } + } + if (CLASS (sched)->state_transition) return CLASS (sched)->state_transition (sched, element, transition); return GST_STATE_SUCCESS; } -/** - * gst_scheduler_remove_element: - * @sched: the schedulerr - * @element: the element to remov - * - * Remove an element from the schedulerr. - */ void -gst_scheduler_remove_element (GstScheduler *sched, GstElement *element) +gst_scheduler_add_scheduler (GstScheduler *sched, GstScheduler *sched2) { - GList *pads; - g_return_if_fail (GST_IS_SCHEDULER (sched)); - g_return_if_fail (GST_IS_ELEMENT (element)); + g_return_if_fail (GST_IS_SCHEDULER (sched2)); - if (CLASS (sched)->remove_element) - CLASS (sched)->remove_element (sched, element); - - for (pads = element->pads; pads; pads = pads->next) { - GstPad *pad = GST_PAD (pads->data); - - if (GST_IS_REAL_PAD (pad)) { - gst_pad_unset_sched (GST_PAD (pads->data)); - } - } + sched->schedulers = g_list_prepend (sched->schedulers, sched2); + sched2->parent_sched = sched; + + if (CLASS (sched)->add_scheduler) + CLASS (sched)->add_scheduler (sched, sched2); } +void +gst_scheduler_remove_scheduler (GstScheduler *sched, GstScheduler *sched2) +{ + g_return_if_fail (GST_IS_SCHEDULER (sched)); + g_return_if_fail (GST_IS_SCHEDULER (sched2)); + + sched->schedulers = g_list_remove (sched->schedulers, sched2); + sched2->parent_sched = NULL; + + if (CLASS (sched)->remove_scheduler) + CLASS (sched)->remove_scheduler (sched, sched2); +} + + /** * gst_scheduler_lock_element: * @sched: the scheduler @@ -315,6 +387,106 @@ gst_scheduler_interrupt (GstScheduler *sched, GstElement *element) return FALSE; } +GstClock* +gst_scheduler_get_clock (GstScheduler *sched) +{ + GstClock *clock = NULL; + + if (GST_FLAG_IS_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK)) { + clock = sched->clock; + } + else { + if (sched->schedulers) { + GList *schedulers = sched->schedulers; + + while (schedulers) { + GstScheduler *scheduler = GST_SCHEDULER (schedulers->data); + + clock = gst_scheduler_get_clock (scheduler); + if (clock) + break; + + schedulers = g_list_next (schedulers); + } + } + if (!clock && sched->clock_providers) { + clock = gst_element_get_clock (GST_ELEMENT (sched->clock_providers->data)); + } + if (!clock && sched->parent_sched == NULL) { + clock = gst_system_clock_obtain (); + } + } + + return clock; +} + +void +gst_scheduler_use_clock (GstScheduler *sched, GstClock *clock) +{ + g_return_if_fail (sched != NULL); + g_return_if_fail (GST_IS_SCHEDULER (sched)); + + GST_FLAG_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK); + sched->clock = clock; +} + +void +gst_scheduler_set_clock (GstScheduler *sched, GstClock *clock) +{ + GList *receivers; + GList *schedulers; + + g_return_if_fail (sched != NULL); + g_return_if_fail (GST_IS_SCHEDULER (sched)); + + receivers = sched->clock_receivers; + schedulers = sched->schedulers; + + sched->current_clock = clock; + + while (receivers) { + GstElement *element = GST_ELEMENT (receivers->data); + + gst_element_set_clock (element, clock); + receivers = g_list_next (receivers); + } + while (schedulers) { + GstScheduler *scheduler = GST_SCHEDULER (schedulers->data); + + gst_scheduler_set_clock (scheduler, clock); + schedulers = g_list_next (schedulers); + } +} + +void +gst_scheduler_auto_clock (GstScheduler *sched) +{ + g_return_if_fail (sched != NULL); + g_return_if_fail (GST_IS_SCHEDULER (sched)); + + GST_FLAG_UNSET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK); + sched->clock = NULL; +} + +/** + * gst_scheduler_clock_wait: + * @sched: the scheduler + * + * Perform one iteration on the schedulerr. + * + * Returns: a boolean indicating something usefull has happened. + */ +GstClockReturn +gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element, GstClock *clock, GstClockTime time) +{ + g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_CLOCK_ERROR); + + if (CLASS (sched)->clock_wait) + return CLASS (sched)->clock_wait (sched, element, clock, time); + + return GST_CLOCK_TIMEOUT; +} + /** * gst_scheduler_iterate: * @sched: the scheduler diff --git a/gst/gstscheduler.h b/gst/gstscheduler.h index 60e38e5..599172d 100644 --- a/gst/gstscheduler.h +++ b/gst/gstscheduler.h @@ -44,6 +44,13 @@ extern "C" { #define GST_IS_SCHEDULER_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SCHEDULER)) +typedef enum { + /* this scheduler works with a fixed clock */ + GST_SCHEDULER_FLAG_FIXED_CLOCK = GST_OBJECT_FLAG_LAST, + + /* padding */ + GST_SCHEDULER_FLAG_LAST = GST_OBJECT_FLAG_LAST + 4, +} GstSchedulerFlags; #define GST_SCHEDULER_PARENT(sched) ((sched)->parent) #define GST_SCHEDULER_STATE(sched) ((sched)->state) @@ -58,11 +65,19 @@ typedef enum { } GstSchedulerState; struct _GstScheduler { - GstObject object; + GstObject object; + + GstElement *parent; + GstScheduler *parent_sched; - GstElement *parent; + GstSchedulerState state; + GstClock *clock; + GstClock *current_clock; - GstSchedulerState state; + GList *clock_providers; + GList *clock_receivers; + + GList *schedulers; }; struct _GstSchedulerClass { @@ -73,6 +88,8 @@ struct _GstSchedulerClass { void (*reset) (GstScheduler *sched); void (*add_element) (GstScheduler *sched, GstElement *element); void (*remove_element) (GstScheduler *sched, GstElement *element); + void (*add_scheduler) (GstScheduler *sched, GstScheduler *sched2); + void (*remove_scheduler) (GstScheduler *sched, GstScheduler *sched2); GstElementStateReturn (*state_transition) (GstScheduler *sched, GstElement *element, gint transition); void (*lock_element) (GstScheduler *sched, GstElement *element); void (*unlock_element) (GstScheduler *sched, GstElement *element); @@ -82,6 +99,8 @@ struct _GstSchedulerClass { void (*pad_connect) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); void (*pad_disconnect) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); void (*pad_select) (GstScheduler *sched, GList *padlist); + GstClockReturn (*clock_wait) (GstScheduler *sched, GstElement *element, + GstClock *clock, GstClockTime time); GstSchedulerState (*iterate) (GstScheduler *sched); /* for debugging */ void (*show) (GstScheduler *sched); @@ -98,6 +117,8 @@ void gst_scheduler_setup (GstScheduler *sched); void gst_scheduler_reset (GstScheduler *sched); void gst_scheduler_add_element (GstScheduler *sched, GstElement *element); void gst_scheduler_remove_element (GstScheduler *sched, GstElement *element); +void gst_scheduler_add_scheduler (GstScheduler *sched, GstScheduler *sched2); +void gst_scheduler_remove_scheduler (GstScheduler *sched, GstScheduler *sched2); GstElementStateReturn gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition); void gst_scheduler_lock_element (GstScheduler *sched, GstElement *element); void gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element); @@ -107,8 +128,17 @@ void gst_scheduler_error (GstScheduler *sched, GstElement *element); void gst_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); void gst_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); GstPad* gst_scheduler_pad_select (GstScheduler *sched, GList *padlist); +GstClock* gst_scheduler_get_clock (GstScheduler *sched); +GstClock* gst_scheduler_get_clock (GstScheduler *sched); +GstClockReturn gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element, + GstClock *clock, GstClockTime time); gboolean gst_scheduler_iterate (GstScheduler *sched); +void gst_scheduler_use_clock (GstScheduler *sched, GstClock *clock); +void gst_scheduler_set_clock (GstScheduler *sched, GstClock *clock); +GstClock* gst_scheduler_get_clock (GstScheduler *sched); +void gst_scheduler_auto_clock (GstScheduler *sched); + void gst_scheduler_show (GstScheduler *sched); /* diff --git a/gst/gstsystemclock.c b/gst/gstsystemclock.c index 7693c4f..cc82428 100644 --- a/gst/gstsystemclock.c +++ b/gst/gstsystemclock.c @@ -34,11 +34,7 @@ static GstClock *_the_system_clock = NULL; static void gst_system_clock_class_init (GstSystemClockClass *klass); static void gst_system_clock_init (GstSystemClock *clock); -static void gst_system_clock_activate (GstClock *clock, gboolean active); -static void gst_system_clock_reset (GstClock *clock); -static void gst_system_clock_set_time (GstClock *clock, GstClockTime time); -static GstClockTime gst_system_clock_get_time (GstClock *clock); -static GstClockReturn gst_system_clock_wait (GstClock *clock, GstClockTime time); +static GstClockTime gst_system_clock_get_internal_time (GstClock *clock); static guint64 gst_system_clock_get_resolution (GstClock *clock); @@ -82,11 +78,7 @@ gst_system_clock_class_init (GstSystemClockClass *klass) parent_class = g_type_class_ref (GST_TYPE_CLOCK); - gstclock_class->activate = gst_system_clock_activate; - gstclock_class->reset = gst_system_clock_reset; - gstclock_class->set_time = gst_system_clock_set_time; - gstclock_class->get_time = gst_system_clock_get_time; - gstclock_class->wait = gst_system_clock_wait; + gstclock_class->get_internal_time = gst_system_clock_get_internal_time; gstclock_class->get_resolution = gst_system_clock_get_resolution; } @@ -105,89 +97,12 @@ gst_system_clock_obtain (void) return _the_system_clock; } -static void -gst_system_clock_activate (GstClock *clock, gboolean active) -{ - GTimeVal timeval; - GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock); - - g_get_current_time (&timeval); - GST_LOCK (clock); - if (active) { - sys_clock->absolute_start = GST_TIMEVAL_TO_TIME (timeval) - sys_clock->current_time;; - } - else { - sys_clock->current_time = GST_TIMEVAL_TO_TIME (timeval) - sys_clock->absolute_start; - } - GST_UNLOCK (clock); -} - -static void -gst_system_clock_set_time (GstClock *clock, GstClockTime time) -{ - GTimeVal timeval; - GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock); - - g_get_current_time (&timeval); - - GST_LOCK (clock); - sys_clock->absolute_start = GST_TIMEVAL_TO_TIME (timeval) - time; - sys_clock->current_time = time; - GST_UNLOCK (clock); -} - -static void -gst_system_clock_reset (GstClock *clock) -{ - gst_system_clock_set_time (clock, 0LL); -} - static GstClockTime -gst_system_clock_get_time (GstClock *clock) -{ - GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock); - GstClockTime res; - - if (!clock->active) { - GST_LOCK (clock); - res = sys_clock->current_time; - } - else { - GTimeVal timeval; - - g_get_current_time (&timeval); - - GST_LOCK (clock); - res = GST_TIMEVAL_TO_TIME (timeval) - sys_clock->absolute_start; - } - GST_UNLOCK (clock); - - return res; -} - -static GstClockReturn -gst_system_clock_wait (GstClock *clock, GstClockTime time) +gst_system_clock_get_internal_time (GstClock *clock) { - GstClockTime target; GTimeVal timeval; - GCond *cond = g_cond_new (); - GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock); - GstClockReturn ret; - - GST_LOCK (clock); - target = time + sys_clock->absolute_start; - - timeval.tv_usec = target % 1000000; - timeval.tv_sec = target / 1000000; - - g_cond_timed_wait (cond, GST_GET_LOCK (clock), &timeval); - GST_UNLOCK (clock); - - ret = GST_CLOCK_TIMEOUT; - - g_cond_free (cond); - - return ret; + g_get_current_time (&timeval); + return GST_TIMEVAL_TO_TIME (timeval); } static guint64 diff --git a/gst/gstsystemclock.h b/gst/gstsystemclock.h index 16c11b3..f972e12 100644 --- a/gst/gstsystemclock.h +++ b/gst/gstsystemclock.h @@ -47,9 +47,6 @@ typedef struct _GstSystemClockClass GstSystemClockClass; struct _GstSystemClock { GstClock clock; - - GstClockTime absolute_start; - GstClockTime current_time; }; struct _GstSystemClockClass { diff --git a/gst/gstthread.c b/gst/gstthread.c index 94e8a61..e6044e1 100644 --- a/gst/gstthread.c +++ b/gst/gstthread.c @@ -140,6 +140,7 @@ gst_thread_init (GstThread *thread) /* we're a manager by default */ GST_FLAG_SET (thread, GST_BIN_FLAG_MANAGER); + GST_FLAG_SET (thread, GST_BIN_SELF_SCHEDULABLE); schedname = gst_schedulerfactory_get_default_name (); diff --git a/gst/gstutils.c b/gst/gstutils.c index 6ee1cbf..d8cc400 100644 --- a/gst/gstutils.c +++ b/gst/gstutils.c @@ -199,28 +199,6 @@ gst_util_get_pointer_arg (GObject * object, const gchar * argname) } /** - * gst_util_get_widget_property: - * @object: the object to query - * @argname: the name of the argument - * - * Retrieves a property of an object as a widget. - * - * Returns: the property of the object - */ -/* COMMENTED OUT BECAUSE WE HAVE NO MORE gtk.h -GtkWidget* -gst_util_get_widget_property (GObject *object, const gchar *argname) -{ - GtkArg arg; - - arg.name = argname; - gtk_object_getv(G_OBJECT(object),1,&arg); - - return GTK_WIDGET(G_VALUE_OBJECT(arg)); -} -*/ - -/** * gst_util_dump_mem: * @mem: a pointer to the memory to dump * @size: the size of the memory block to dump @@ -448,7 +426,6 @@ gst_util_set_object_arg (GObject * object, const gchar * name, const gchar * val #include "gstpad.h" #include "gsttype.h" #include "gstprops.h" -#include "gstpropsprivate.h" static void string_append_indent (GString * str, gint count) @@ -460,15 +437,16 @@ string_append_indent (GString * str, gint count) } static void -gst_print_props (GString * buf, gint indent, GList * props, gboolean showname) +gst_print_props (GString *buf, gint indent, GList *props, gboolean showname) { GList *elem; guint width = 0; + GstPropsType type; if (showname) for (elem = props; elem; elem = g_list_next (elem)) { GstPropsEntry *prop = elem->data; - const gchar *name = g_quark_to_string (prop->propid); + const gchar *name = gst_props_entry_get_name (prop); if (width < strlen (name)) width = strlen (name); @@ -479,45 +457,76 @@ gst_print_props (GString * buf, gint indent, GList * props, gboolean showname) string_append_indent (buf, indent); if (showname) { - const gchar *name = g_quark_to_string (prop->propid); + const gchar *name = gst_props_entry_get_name (prop); g_string_append (buf, name); string_append_indent (buf, 2 + width - strlen (name)); } - switch (prop->propstype) { - case GST_PROPS_INT_ID: - g_string_append_printf (buf, "%d (int)\n", prop->data.int_data); + type = gst_props_entry_get_type (prop); + switch (type) { + case GST_PROPS_INT_TYPE: + { + gint val; + gst_props_entry_get_int (prop, &val); + g_string_append_printf (buf, "%d (int)\n", val); break; - case GST_PROPS_INT_RANGE_ID: - g_string_append_printf (buf, "%d - %d (int)\n", - prop->data.int_range_data.min, prop->data.int_range_data.max); + } + case GST_PROPS_INT_RANGE_TYPE: + { + gint min, max; + gst_props_entry_get_int_range (prop, &min, &max); + g_string_append_printf (buf, "%d - %d (int)\n", min, max); break; - case GST_PROPS_FLOAT_ID: - g_string_append_printf (buf, "%f (float)\n", prop->data.float_data); + } + case GST_PROPS_FLOAT_TYPE: + { + gfloat val; + gst_props_entry_get_float (prop, &val); + g_string_append_printf (buf, "%f (float)\n", val); break; - case GST_PROPS_FLOAT_RANGE_ID: - g_string_append_printf (buf, "%f - %f (float)\n", - prop->data.float_range_data.min, prop->data.float_range_data.max); + } + case GST_PROPS_FLOAT_RANGE_TYPE: + { + gfloat min, max; + gst_props_entry_get_float_range (prop, &min, &max); + g_string_append_printf (buf, "%f - %f (float)\n", min, max); break; - case GST_PROPS_BOOL_ID: - g_string_append_printf (buf, "%s\n", prop->data.bool_data ? "TRUE" : "FALSE"); + } + case GST_PROPS_BOOL_TYPE: + { + gboolean val; + gst_props_entry_get_boolean (prop, &val); + g_string_append_printf (buf, "%s\n", val ? "TRUE" : "FALSE"); break; - case GST_PROPS_STRING_ID: - g_string_append_printf (buf, "\"%s\"\n", prop->data.string_data.string); + } + case GST_PROPS_STRING_TYPE: + { + const gchar *val; + gst_props_entry_get_string (prop, &val); + g_string_append_printf (buf, "\"%s\"\n", val); break; - case GST_PROPS_FOURCC_ID: + } + case GST_PROPS_FOURCC_TYPE: + { + guint32 val; + gst_props_entry_get_fourcc_int (prop, &val); g_string_append_printf (buf, "'%c%c%c%c' (fourcc)\n", - prop->data.fourcc_data & 0xff, - prop->data.fourcc_data >> 8 & 0xff, - prop->data.fourcc_data >> 16 & 0xff, - prop->data.fourcc_data >> 24 & 0xff); + (gchar)( val & 0xff), + (gchar)((val >> 8) & 0xff), + (gchar)((val >> 16) & 0xff), + (gchar)((val >> 24) & 0xff)); break; - case GST_PROPS_LIST_ID: - gst_print_props (buf, indent + 2, prop->data.list_data.entries, FALSE); + } + case GST_PROPS_LIST_TYPE: + { + const GList *list; + gst_props_entry_get_list (prop, &list); + gst_print_props (buf, indent + 2, (GList *)list, FALSE); break; + } default: - g_string_append_printf (buf, "unknown proptype %d\n", prop->propstype); + g_string_append_printf (buf, "unknown proptype %d\n", type); break; } } diff --git a/gst/gstutils.h b/gst/gstutils.h index 9124cfe..4b8a46c 100644 --- a/gst/gstutils.h +++ b/gst/gstutils.h @@ -41,8 +41,7 @@ gfloat gst_util_get_float_arg (GObject *object, const gchar *argname); gdouble gst_util_get_double_arg (GObject *object, const gchar *argname); const gchar* gst_util_get_string_arg (GObject *object, const gchar *argname); gpointer gst_util_get_pointer_arg (GObject *object, const gchar *argname); -/*GtkWidget* gst_util_get_widget_property (GObject *object, const gchar *argname);*/ -void gst_util_set_value_from_string(GValue *value, const gchar *value_str); +void gst_util_set_value_from_string (GValue *value, const gchar *value_str); void gst_util_set_object_arg (GObject *object, const gchar *name, const gchar *value); void gst_util_dump_mem (guchar *mem, guint size); diff --git a/gst/schedulers/Makefile.am b/gst/schedulers/Makefile.am index f7abe84..8038929 100644 --- a/gst/schedulers/Makefile.am +++ b/gst/schedulers/Makefile.am @@ -1,6 +1,6 @@ plugindir = $(libdir)/gst -plugin_LTLIBRARIES = libgstbasicscheduler.la libgststandardscheduler.la +plugin_LTLIBRARIES = libgstbasicscheduler.la libgststandardscheduler.la libgstfastscheduler.la libgstbasicscheduler_la_SOURCES = gstbasicscheduler.c libgstbasicscheduler_la_CFLAGS = $(GST_CFLAGS) @@ -12,6 +12,11 @@ libgststandardscheduler_la_CFLAGS = $(GST_CFLAGS) -I$(top_srcdir)/libs/ext/cothr libgststandardscheduler_la_LIBADD = $(top_builddir)/libs/ext/cothreads/cothreads/libcothreads-gthreads.la libgststandardscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstfastscheduler_la_SOURCES = gstfastscheduler.c +libgstfastscheduler_la_CFLAGS = $(GST_CFLAGS) +libgstfastscheduler_la_LIBADD = $(GST_LIBS) ../libcothreads.la +libgstfastscheduler_la_LDFLAGS = @GST_LT_LDFLAGS@ + ## this is a REALLY evil hack ## but we need to keep it as long as we have libs/gst and libs/ext $(top_builddir)/libs/ext/cothreads/cothreads/libcothreads-gthreads.la: diff --git a/gst/schedulers/gstbasicscheduler.c b/gst/schedulers/gstbasicscheduler.c index 169ac06..4176728 100644 --- a/gst/schedulers/gstbasicscheduler.c +++ b/gst/schedulers/gstbasicscheduler.c @@ -72,7 +72,7 @@ typedef enum { typedef enum { /* something important has changed inside the scheduler */ - GST_BASIC_SCHEDULER_CHANGE = GST_OBJECT_FLAG_LAST, + GST_BASIC_SCHEDULER_CHANGE = GST_SCHEDULER_FLAG_LAST, } GstBasicSchedulerFlags; struct _GstBasicScheduler { @@ -112,6 +112,8 @@ static void gst_basic_scheduler_error (GstScheduler *sched, GstElement *elem static void gst_basic_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); static void gst_basic_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); static GstPad* gst_basic_scheduler_pad_select (GstScheduler *sched, GList *padlist); +static GstClockReturn gst_basic_scheduler_clock_wait (GstScheduler *sched, GstElement *element, + GstClock *clock, GstClockTime time); static GstSchedulerState gst_basic_scheduler_iterate (GstScheduler *sched); @@ -169,6 +171,7 @@ gst_basic_scheduler_class_init (GstBasicSchedulerClass * klass) gstscheduler_class->pad_connect = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_connect); gstscheduler_class->pad_disconnect = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_disconnect); gstscheduler_class->pad_select = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_select); + gstscheduler_class->clock_wait = GST_DEBUG_FUNCPTR (gst_basic_scheduler_clock_wait); gstscheduler_class->iterate = GST_DEBUG_FUNCPTR (gst_basic_scheduler_iterate); gstscheduler_class->show = GST_DEBUG_FUNCPTR (gst_basic_scheduler_show); @@ -424,6 +427,9 @@ gst_basic_scheduler_gethandler_proxy (GstPad * pad) if (GST_RPAD_PEER (peer) != (GstRealPad *) pad) { GST_DEBUG (GST_CAT_DATAFLOW, "new pad in mid-switch!"); pad = (GstPad *) GST_RPAD_PEER (peer); + if (!pad) { + gst_element_error (GST_ELEMENT (GST_PAD_PARENT (peer)), "pad unconnected"); + } } } GST_DEBUG (GST_CAT_DATAFLOW, "done switching"); @@ -530,7 +536,7 @@ gst_basic_scheduler_cothreaded_chain (GstBin * bin, GstSchedulerChain * chain) if (!GST_IS_REAL_PAD (pad)) continue; - peerpad = GST_PAD (GST_RPAD_PEER (pad)); + peerpad = GST_PAD_PEER (pad); /* if the element is DECOUPLED or outside the manager, we have to chain */ if ((wrapper_function == NULL) || @@ -677,6 +683,7 @@ gst_basic_scheduler_chain_enable_element (GstSchedulerChain * chain, GstElement /* notify the scheduler that something changed */ GST_FLAG_SET(chain->sched, GST_BASIC_SCHEDULER_CHANGE); + //GST_FLAG_UNSET(element, GST_ELEMENT_COTHREAD_STOPPING); /* reschedule the chain */ return gst_basic_scheduler_cothreaded_chain (GST_BIN (GST_SCHEDULER (chain->sched)->parent), chain); @@ -696,6 +703,7 @@ gst_basic_scheduler_chain_disable_element (GstSchedulerChain * chain, GstElement /* notify the scheduler that something changed */ GST_FLAG_SET(chain->sched, GST_BASIC_SCHEDULER_CHANGE); + GST_FLAG_SET(element, GST_ELEMENT_COTHREAD_STOPPING); /* reschedule the chain */ /* FIXME this should be done only if manager state != NULL */ @@ -969,19 +977,6 @@ gst_basic_scheduler_remove_element (GstScheduler * sched, GstElement * element) /* find what chain the element is in */ chain = gst_basic_scheduler_find_chain (bsched, element); - if (GST_ELEMENT_IS_COTHREAD_STOPPING (element)) { - GstElement *entry = GST_ELEMENT (cothread_get_private (cothread_current ())); - - if (entry == element) { - g_warning ("removing currently running element! %s", GST_ELEMENT_NAME (entry)); - } - else if (entry) { - GST_INFO (GST_CAT_SCHEDULING, "moving stopping to element \"%s\"", - GST_ELEMENT_NAME (entry)); - GST_FLAG_SET (entry, GST_ELEMENT_COTHREAD_STOPPING); - } - } - /* remove it from its chain */ gst_basic_scheduler_chain_remove_element (chain, element); @@ -1196,6 +1191,13 @@ gst_basic_scheduler_pad_select (GstScheduler * sched, GList * padlist) return pad; } +static GstClockReturn +gst_basic_scheduler_clock_wait (GstScheduler *sched, GstElement *element, + GstClock *clock, GstClockTime time) +{ + return gst_clock_wait (clock, time); +} + static GstSchedulerState gst_basic_scheduler_iterate (GstScheduler * sched) { diff --git a/gst/schedulers/gstfastscheduler.c b/gst/schedulers/gstfastscheduler.c new file mode 100644 index 0000000..45a1264 --- /dev/null +++ b/gst/schedulers/gstfastscheduler.c @@ -0,0 +1,1095 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstscheduler.c: Default scheduling code for most cases + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/*#define GST_DEBUG_ENABLED */ +#include +#include <../cothreads.h> + +typedef struct _GstSchedulerChain GstSchedulerChain; + +#define GST_PAD_THREADSTATE(pad) (cothread_state*) (GST_PAD_CAST (pad)->sched_private) +#define GST_ELEMENT_THREADSTATE(elem) (cothread_state*) (GST_ELEMENT_CAST (elem)->sched_private) +#define GST_BIN_THREADCONTEXT(bin) (cothread_context*) (GST_BIN_CAST (bin)->sched_private) + +#define GST_ELEMENT_COTHREAD_STOPPING GST_ELEMENT_SCHEDULER_PRIVATE1 +#define GST_ELEMENT_IS_COTHREAD_STOPPING(element) GST_FLAG_IS_SET((element), GST_ELEMENT_COTHREAD_STOPPING) +#define GST_ELEMENT_INTERRUPTED GST_ELEMENT_SCHEDULER_PRIVATE2 +#define GST_ELEMENT_IS_INTERRUPTED(element) GST_FLAG_IS_SET((element), GST_ELEMENT_INTERRUPTED) + +typedef struct _GstFastScheduler GstFastScheduler; +typedef struct _GstFastSchedulerClass GstFastSchedulerClass; + +struct _GstSchedulerChain { + GstFastScheduler *sched; + + GList *disabled; + + GList *elements; + gint num_elements; + + GstElement *entry; + + GList *cothreaded_elements; + gint num_cothreaded; + + gboolean schedule; +}; + +#define GST_TYPE_FAST_SCHEDULER \ + (gst_fast_scheduler_get_type()) +#define GST_FAST_SCHEDULER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FAST_SCHEDULER,GstFastScheduler)) +#define GST_FAST_SCHEDULER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FAST_SCHEDULER,GstFastSchedulerClass)) +#define GST_IS_FAST_SCHEDULER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FAST_SCHEDULER)) +#define GST_IS_FAST_SCHEDULER_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FAST_SCHEDULER)) + +#define GST_FAST_SCHEDULER_CAST(sched) ((GstFastScheduler *)(sched)) + +typedef enum { + GST_FAST_SCHEDULER_STATE_NONE, + GST_FAST_SCHEDULER_STATE_STOPPED, + GST_FAST_SCHEDULER_STATE_ERROR, + GST_FAST_SCHEDULER_STATE_RUNNING, +} GstFastSchedulerState; + +struct _GstFastScheduler { + GstScheduler parent; + + GList *elements; + gint num_elements; + + GList *chains; + gint num_chains; + + GstFastSchedulerState state; + +}; + +struct _GstFastSchedulerClass { + GstSchedulerClass parent_class; +}; + +static GType _gst_fast_scheduler_type = 0; + +static void gst_fast_scheduler_class_init (GstFastSchedulerClass * klass); +static void gst_fast_scheduler_init (GstFastScheduler * scheduler); + +static void gst_fast_scheduler_dispose (GObject *object); + +static void gst_fast_scheduler_setup (GstScheduler *sched); +static void gst_fast_scheduler_reset (GstScheduler *sched); +static void gst_fast_scheduler_add_element (GstScheduler *sched, GstElement *element); +static void gst_fast_scheduler_remove_element (GstScheduler *sched, GstElement *element); +static GstElementStateReturn + gst_fast_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition); +static void gst_fast_scheduler_lock_element (GstScheduler *sched, GstElement *element); +static void gst_fast_scheduler_unlock_element (GstScheduler *sched, GstElement *element); +static void gst_fast_scheduler_yield (GstScheduler *sched, GstElement *element); +static gboolean gst_fast_scheduler_interrupt (GstScheduler *sched, GstElement *element); +static void gst_fast_scheduler_error (GstScheduler *sched, GstElement *element); +static void gst_fast_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); +static void gst_fast_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); +static GstPad* gst_fast_scheduler_pad_select (GstScheduler *sched, GList *padlist); +static GstSchedulerState + gst_fast_scheduler_iterate (GstScheduler *sched); + +static void gst_fast_scheduler_show (GstScheduler *sched); + +static GstSchedulerClass *parent_class = NULL; + +static GType +gst_fast_scheduler_get_type (void) +{ + if (!_gst_fast_scheduler_type) { + static const GTypeInfo scheduler_info = { + sizeof (GstFastSchedulerClass), + NULL, + NULL, + (GClassInitFunc) gst_fast_scheduler_class_init, + NULL, + NULL, + sizeof (GstFastScheduler), + 0, + (GInstanceInitFunc) gst_fast_scheduler_init, + NULL + }; + + _gst_fast_scheduler_type = g_type_register_static (GST_TYPE_SCHEDULER, "GstFastScheduler", &scheduler_info, 0); + } + return _gst_fast_scheduler_type; +} + +static void +gst_fast_scheduler_class_init (GstFastSchedulerClass * klass) +{ + GObjectClass *gobject_class; + GstObjectClass *gstobject_class; + GstSchedulerClass *gstscheduler_class; + + gobject_class = (GObjectClass*)klass; + gstobject_class = (GstObjectClass*)klass; + gstscheduler_class = (GstSchedulerClass*)klass; + + parent_class = g_type_class_ref (GST_TYPE_SCHEDULER); + + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_fast_scheduler_dispose); + + gstscheduler_class->setup = GST_DEBUG_FUNCPTR (gst_fast_scheduler_setup); + gstscheduler_class->reset = GST_DEBUG_FUNCPTR (gst_fast_scheduler_reset); + gstscheduler_class->add_element = GST_DEBUG_FUNCPTR (gst_fast_scheduler_add_element); + gstscheduler_class->remove_element = GST_DEBUG_FUNCPTR (gst_fast_scheduler_remove_element); + gstscheduler_class->state_transition = GST_DEBUG_FUNCPTR (gst_fast_scheduler_state_transition); + gstscheduler_class->lock_element = GST_DEBUG_FUNCPTR (gst_fast_scheduler_lock_element); + gstscheduler_class->unlock_element = GST_DEBUG_FUNCPTR (gst_fast_scheduler_unlock_element); + gstscheduler_class->yield = GST_DEBUG_FUNCPTR (gst_fast_scheduler_yield); + gstscheduler_class->interrupt = GST_DEBUG_FUNCPTR (gst_fast_scheduler_interrupt); + gstscheduler_class->error = GST_DEBUG_FUNCPTR (gst_fast_scheduler_error); + gstscheduler_class->pad_connect = GST_DEBUG_FUNCPTR (gst_fast_scheduler_pad_connect); + gstscheduler_class->pad_disconnect = GST_DEBUG_FUNCPTR (gst_fast_scheduler_pad_disconnect); + gstscheduler_class->pad_select = GST_DEBUG_FUNCPTR (gst_fast_scheduler_pad_select); + gstscheduler_class->iterate = GST_DEBUG_FUNCPTR (gst_fast_scheduler_iterate); +} + +static void +gst_fast_scheduler_init (GstFastScheduler *scheduler) +{ + scheduler->elements = NULL; + scheduler->num_elements = 0; + scheduler->chains = NULL; + scheduler->num_chains = 0; +} + +static void +gst_fast_scheduler_dispose (GObject *object) +{ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstSchedulerFactory *factory; + + gst_plugin_set_longname (plugin, "A fast scheduler"); + + factory = gst_schedulerfactory_new ("fast", + "A fast scheduler, it uses cothreads", + gst_fast_scheduler_get_type()); + + if (factory != NULL) { + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + } + else { + g_warning ("could not register scheduler: fast"); + } + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "gstfastscheduler", + plugin_init +}; + +static int +gst_fast_scheduler_loopfunc_wrapper (int argc, char *argv[]) +{ + GstElement *element = GST_ELEMENT_CAST (argv); + G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element); + + GST_DEBUG_ENTER ("(%d,'%s')", argc, name); + + do { + GST_DEBUG (GST_CAT_DATAFLOW, "calling loopfunc %s for element %s\n", + GST_DEBUG_FUNCPTR_NAME (element->loopfunc), name); + (element->loopfunc) (element); + GST_DEBUG (GST_CAT_DATAFLOW, "element %s ended loop function\n", name); + + } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); + GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING); + + GST_DEBUG_LEAVE ("(%d,'%s')", argc, name); + return 0; +} + +static void +gst_fast_scheduler_chainfunc_proxy (GstPad *pad, GstBuffer *buffer) +{ + GstElement *element = GST_PAD_PARENT (pad); + + GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad)); + + GST_RPAD_BUFPEN (pad) = buffer; + + while (GST_RPAD_BUFPEN (pad) != NULL) { + if (GST_ELEMENT_THREADSTATE (element)) { + cothread_switch (GST_ELEMENT_THREADSTATE (element)); + } + else { + g_assert_not_reached(); + } + } + GST_DEBUG_LEAVE ("(%s:%s)", GST_DEBUG_PAD_NAME (pad)); +} + +static GstBuffer* +gst_fast_scheduler_getfunc_proxy (GstPad *pad) +{ + GstElement *element = GST_PAD_PARENT (pad); + GstPad *peer = GST_PAD_CAST (GST_RPAD_PEER (pad)); + GstBuffer *buf; + + GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad)); + + while (GST_RPAD_BUFPEN (peer) == NULL) { + if (GST_ELEMENT_THREADSTATE (element)) { + cothread_switch (GST_ELEMENT_THREADSTATE (element)); + } + else { + g_assert_not_reached(); + } + } + + GST_DEBUG_LEAVE ("(%s:%s)", GST_DEBUG_PAD_NAME (pad)); + buf = GST_RPAD_BUFPEN (peer); + GST_RPAD_BUFPEN (peer) = NULL; + + return buf; +} + +static gboolean +gst_fast_scheduler_cothreaded_element (GstBin * bin, GstElement *element) +{ + GList *elements; + cothread_func wrapper_function; + GList *pads; + + GST_DEBUG (GST_CAT_SCHEDULING, "element is using COTHREADS\n"); + + g_assert (GST_BIN_THREADCONTEXT (bin) != NULL); + + wrapper_function = GST_DEBUG_FUNCPTR (gst_fast_scheduler_loopfunc_wrapper); + + if (GST_ELEMENT_THREADSTATE (element) == NULL) { + GST_ELEMENT_THREADSTATE (element) = cothread_create (GST_BIN_THREADCONTEXT (bin)); + if (GST_ELEMENT_THREADSTATE (element) == NULL) { + gst_element_error (element, "could not create cothread for \"%s\"", + GST_ELEMENT_NAME (element), NULL); + return FALSE; + } + GST_DEBUG (GST_CAT_SCHEDULING, "created cothread %p for '%s'\n", + GST_ELEMENT_THREADSTATE (element), + GST_ELEMENT_NAME (element)); + cothread_setfunc (GST_ELEMENT_THREADSTATE (element), wrapper_function, 0, (char **) element); + GST_DEBUG (GST_CAT_SCHEDULING, "set wrapper function for '%s' to &%s\n", + GST_ELEMENT_NAME (element), GST_DEBUG_FUNCPTR_NAME (wrapper_function)); + } + + pads = gst_element_get_pad_list (element); + + while (pads) { + GstPad *pad = GST_PAD_CAST (pads->data); + pads = g_list_next (pads); + + if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) { + GST_DEBUG (GST_CAT_SCHEDULING, "setting gethandler to getfunc_proxy for %s:%s\n", GST_DEBUG_PAD_NAME (pad)); + GST_RPAD_GETHANDLER (pad) = gst_fast_scheduler_getfunc_proxy; + } + else { + GST_DEBUG (GST_CAT_SCHEDULING, "setting chainhandler to chainfunc_proxy for %s:%s\n", GST_DEBUG_PAD_NAME (pad)); + GST_RPAD_CHAINHANDLER (pad) = gst_fast_scheduler_chainfunc_proxy; + } + } + + return TRUE; +} + +static gboolean +gst_fast_scheduler_chained_element (GstBin *bin, GstElement *element) { + GList *pads; + GstPad *pad; + + GST_DEBUG (GST_CAT_SCHEDULING,"chain entered\n"); + + // walk through all the pads + pads = gst_element_get_pad_list (element); + while (pads) { + pad = GST_PAD (pads->data); + pads = g_list_next (pads); + if (!GST_IS_REAL_PAD (pad)) + continue; + + if (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK) { + GST_DEBUG (GST_CAT_SCHEDULING,"copying chain function into chain handler for %s:%s\n",GST_DEBUG_PAD_NAME (pad)); + GST_RPAD_CHAINHANDLER (pad) = GST_RPAD_CHAINFUNC (pad); + } else { + GST_DEBUG (GST_CAT_SCHEDULING,"copying get function into get handler for %s:%s\n",GST_DEBUG_PAD_NAME (pad)); + if (!GST_RPAD_GETFUNC (pad)) + GST_RPAD_GETHANDLER (pad) = gst_fast_scheduler_getfunc_proxy; + else + GST_RPAD_GETHANDLER (pad) = GST_RPAD_GETFUNC (pad); + } + } + + return TRUE; +} + + +static GstSchedulerChain * +gst_fast_scheduler_chain_new (GstFastScheduler * sched) +{ + GstSchedulerChain *chain = g_new (GstSchedulerChain, 1); + + /* initialize the chain with sane values */ + chain->sched = sched; + chain->disabled = NULL; + chain->elements = NULL; + chain->num_elements = 0; + chain->entry = NULL; + chain->cothreaded_elements = NULL; + chain->num_cothreaded = 0; + chain->schedule = FALSE; + + /* add the chain to the schedulers' list of chains */ + sched->chains = g_list_prepend (sched->chains, chain); + sched->num_chains++; + + GST_INFO (GST_CAT_SCHEDULING, "created new chain %p, now are %d chains in sched %p", + chain, sched->num_chains, sched); + + return chain; +} + +static void +gst_fast_scheduler_chain_destroy (GstSchedulerChain * chain) +{ + GstFastScheduler *sched = chain->sched; + + + /* remove the chain from the schedulers' list of chains */ + sched->chains = g_list_remove (sched->chains, chain); + sched->num_chains--; + + /* destroy the chain */ + g_list_free (chain->disabled); /* should be empty... */ + g_list_free (chain->elements); /* ditto */ + + GST_INFO (GST_CAT_SCHEDULING, "destroyed chain %p, now are %d chains in sched %p", chain, + sched->num_chains, sched); + + g_free (chain); +} + +static gboolean +gst_fast_scheduler_chain_enable_element (GstSchedulerChain * chain, GstElement * element) +{ + GST_INFO (GST_CAT_SCHEDULING, "enabling element \"%s\" in chain %p, %d cothreaded elements", + GST_ELEMENT_NAME (element), chain, chain->num_cothreaded); + + /* remove from disabled list */ + chain->disabled = g_list_remove (chain->disabled, element); + + /* add to elements list */ + chain->elements = g_list_prepend (chain->elements, element); + + /* reschedule the chain */ + if (element->loopfunc) { + chain->cothreaded_elements = g_list_prepend (chain->cothreaded_elements, element); + chain->num_cothreaded++; + + return gst_fast_scheduler_cothreaded_element (GST_BIN (GST_SCHEDULER (chain->sched)->parent), element); + } + else { + if (element->numsinkpads == 0 || GST_ELEMENT_IS_DECOUPLED (element)) { + chain->entry = element; + } + + return gst_fast_scheduler_chained_element (GST_BIN (GST_SCHEDULER (chain->sched)->parent), element); + } +} + +static void +gst_fast_scheduler_chain_disable_element (GstSchedulerChain * chain, GstElement * element) +{ + GST_INFO (GST_CAT_SCHEDULING, "disabling element \"%s\" in chain %p", GST_ELEMENT_NAME (element), + chain); + + /* remove from elements list */ + chain->elements = g_list_remove (chain->elements, element); + + /* add to disabled list */ + chain->disabled = g_list_prepend (chain->disabled, element); + + if (element->loopfunc) { + chain->cothreaded_elements = g_list_remove (chain->cothreaded_elements, element); + chain->num_cothreaded--; + } + else { + if (chain->entry == element) + chain->entry = NULL; + } +} + +static void +gst_fast_scheduler_chain_add_element (GstSchedulerChain * chain, GstElement * element) +{ + GST_INFO (GST_CAT_SCHEDULING, "adding element \"%s\" to chain %p", GST_ELEMENT_NAME (element), + chain); + + /* set the sched pointer for the element */ + element->sched = GST_SCHEDULER (chain->sched); + + /* add the element to the list of 'disabled' elements */ + chain->disabled = g_list_prepend (chain->disabled, element); + chain->num_elements++; +} + +static void +gst_fast_scheduler_chain_remove_element (GstSchedulerChain * chain, GstElement * element) +{ + GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from chain %p", GST_ELEMENT_NAME (element), + chain); + + /* if it's active, deactivate it */ + if (g_list_find (chain->elements, element)) { + gst_fast_scheduler_chain_disable_element (chain, element); + } + /* we have to check for a threadstate here because a queue doesn't have one */ + if (GST_ELEMENT_THREADSTATE (element)) { + cothread_free (GST_ELEMENT_THREADSTATE (element)); + GST_ELEMENT_THREADSTATE (element) = NULL; + } + + /* remove the element from the list of elements */ + chain->disabled = g_list_remove (chain->disabled, element); + chain->num_elements--; + + /* if there are no more elements in the chain, destroy the chain */ + if (chain->num_elements == 0) + gst_fast_scheduler_chain_destroy (chain); +} + +static void +gst_fast_scheduler_chain_elements (GstFastScheduler * sched, GstElement * element1, GstElement * element2) +{ + GList *chains; + GstSchedulerChain *chain; + GstSchedulerChain *chain1 = NULL, *chain2 = NULL; + GstElement *element; + + /* first find the chains that hold the two */ + chains = sched->chains; + while (chains) { + chain = (GstSchedulerChain *) (chains->data); + chains = g_list_next (chains); + + if (g_list_find (chain->disabled, element1)) + chain1 = chain; + else if (g_list_find (chain->elements, element1)) + chain1 = chain; + + if (g_list_find (chain->disabled, element2)) + chain2 = chain; + else if (g_list_find (chain->elements, element2)) + chain2 = chain; + } + + /* first check to see if they're in the same chain, we're done if that's the case */ + if ((chain1 != NULL) && (chain1 == chain2)) { + GST_INFO (GST_CAT_SCHEDULING, "elements are already in the same chain"); + return; + } + + /* now, if neither element has a chain, create one */ + if ((chain1 == NULL) && (chain2 == NULL)) { + GST_INFO (GST_CAT_SCHEDULING, "creating new chain to hold two new elements"); + chain = gst_fast_scheduler_chain_new (sched); + gst_fast_scheduler_chain_add_element (chain, element1); + gst_fast_scheduler_chain_add_element (chain, element2); + + /* otherwise if both have chains already, join them */ + } + else if ((chain1 != NULL) && (chain2 != NULL)) { + GST_INFO (GST_CAT_SCHEDULING, "merging chain %p into chain %p", chain2, chain1); + /* take the contents of chain2 and merge them into chain1 */ + chain1->disabled = g_list_concat (chain1->disabled, g_list_copy (chain2->disabled)); + chain1->elements = g_list_concat (chain1->elements, g_list_copy (chain2->elements)); + //chain1->cothreaded_elements = g_list_concat (chain1->cothreaded_elements, g_list_copy (chain2->cothreaded_elements)); + chain1->num_elements += chain2->num_elements; + //chain1->num_cothreaded += chain2->num_cothreaded; + + gst_fast_scheduler_chain_destroy (chain2); + + /* otherwise one has a chain already, the other doesn't */ + } + else { + /* pick out which one has the chain, and which doesn't */ + if (chain1 != NULL) + chain = chain1, element = element2; + else + chain = chain2, element = element1; + + GST_INFO (GST_CAT_SCHEDULING, "adding element to existing chain"); + gst_fast_scheduler_chain_add_element (chain, element); + } +} + + +/* find the chain within the scheduler that holds the element, if any */ +static GstSchedulerChain * +gst_fast_scheduler_find_chain (GstFastScheduler * sched, GstElement * element) +{ + GList *chains; + GstSchedulerChain *chain; + + GST_INFO (GST_CAT_SCHEDULING, "searching for element \"%s\" in chains", + GST_ELEMENT_NAME (element)); + + chains = sched->chains; + while (chains) { + chain = (GstSchedulerChain *) (chains->data); + chains = g_list_next (chains); + + if (g_list_find (chain->elements, element)) + return chain; + if (g_list_find (chain->disabled, element)) + return chain; + } + + return NULL; +} + +static void +gst_fast_scheduler_chain_recursive_add (GstSchedulerChain * chain, GstElement * element) +{ + GList *pads; + GstPad *pad; + GstElement *peerelement; + + /* add the element to the chain */ + gst_fast_scheduler_chain_add_element (chain, element); + + GST_DEBUG (GST_CAT_SCHEDULING, "recursing on element \"%s\"\n", GST_ELEMENT_NAME (element)); + /* now go through all the pads and see which peers can be added */ + pads = element->pads; + while (pads) { + pad = GST_PAD (pads->data); + pads = g_list_next (pads); + + GST_DEBUG (GST_CAT_SCHEDULING, "have pad %s:%s, checking for valid peer\n", + GST_DEBUG_PAD_NAME (pad)); + /* if the peer exists and could be in the same chain */ + if (GST_PAD_PEER (pad)) { + GST_DEBUG (GST_CAT_SCHEDULING, "has peer %s:%s\n", GST_DEBUG_PAD_NAME (GST_PAD_PEER (pad))); + peerelement = GST_PAD_PARENT (GST_PAD_PEER (pad)); + if (GST_ELEMENT_SCHED (GST_PAD_PARENT (pad)) == GST_ELEMENT_SCHED (peerelement)) { + GST_DEBUG (GST_CAT_SCHEDULING, "peer \"%s\" is valid for same chain\n", + GST_ELEMENT_NAME (peerelement)); + /* if it's not already in a chain, add it to this one */ + if (gst_fast_scheduler_find_chain (chain->sched, peerelement) == NULL) { + gst_fast_scheduler_chain_recursive_add (chain, peerelement); + } + } + } + } +} + +/* + * Entry points for this scheduler. + */ +static void +gst_fast_scheduler_setup (GstScheduler *sched) +{ + GstBin *bin = GST_BIN (sched->parent); + + /* first create thread context */ + if (GST_BIN_THREADCONTEXT (bin) == NULL) { + GST_DEBUG (GST_CAT_SCHEDULING, "initializing cothread context\n"); + GST_BIN_THREADCONTEXT (bin) = cothread_context_init (); + } +} + +static void +gst_fast_scheduler_reset (GstScheduler *sched) +{ + cothread_context *ctx; + GstBin *bin = GST_BIN (GST_SCHEDULER_PARENT (sched)); + GList *elements = GST_FAST_SCHEDULER_CAST (sched)->elements; + GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched); + + while (elements) { + GST_ELEMENT_THREADSTATE (elements->data) = NULL; + elements = g_list_next (elements); + } + + ctx = GST_BIN_THREADCONTEXT (GST_SCHEDULER_PARENT (sched)); + + cothread_context_free (ctx); + + GST_BIN_THREADCONTEXT (GST_SCHEDULER_PARENT (sched)) = NULL; +} + +static void +gst_fast_scheduler_add_element (GstScheduler * sched, GstElement * element) +{ + GList *pads; + GstPad *pad; + GstElement *peerelement; + GstSchedulerChain *chain; + GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched); + + /* if it's already in this scheduler, don't bother doing anything */ + if (GST_ELEMENT_SCHED (element) == sched) + return; + + GST_INFO (GST_CAT_SCHEDULING, "adding element \"%s\" to scheduler", GST_ELEMENT_NAME (element)); + + /* if the element already has a different scheduler, remove the element from it */ + if (GST_ELEMENT_SCHED (element)) { + gst_fast_scheduler_remove_element (GST_ELEMENT_SCHED (element), element); + } + + /* set the sched pointer in the element itself */ + GST_ELEMENT_SCHED (element) = sched; + + /* only deal with elements after this point, not bins */ + /* exception is made for Bin's that are schedulable, like the autoplugger */ + if (GST_IS_BIN (element) && !GST_FLAG_IS_SET (element, GST_BIN_SELF_SCHEDULABLE)) + return; + + /* first add it to the list of elements that are to be scheduled */ + bsched->elements = g_list_prepend (bsched->elements, element); + bsched->num_elements++; + + /* create a chain to hold it, and add */ + chain = gst_fast_scheduler_chain_new (bsched); + gst_fast_scheduler_chain_add_element (chain, element); + + /* set the sched pointer in all the pads */ + pads = element->pads; + while (pads) { + pad = GST_PAD (pads->data); + pads = g_list_next (pads); + + /* we only operate on real pads */ + if (!GST_IS_REAL_PAD (pad)) + continue; + + /* set the pad's sched pointer */ + gst_pad_set_sched (pad, sched); + + /* if the peer element exists and is a candidate */ + if (GST_PAD_PEER (pad)) { + peerelement = GST_PAD_PARENT (GST_PAD_PEER (pad)); + if (GST_ELEMENT_SCHED (element) == GST_ELEMENT_SCHED (peerelement)) { + GST_INFO (GST_CAT_SCHEDULING, "peer is in same scheduler, chaining together"); + /* make sure that the two elements are in the same chain */ + gst_fast_scheduler_chain_elements (bsched, element, peerelement); + } + } + } +} + +static void +gst_fast_scheduler_remove_element (GstScheduler * sched, GstElement * element) +{ + GstSchedulerChain *chain; + GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched); + + if (g_list_find (bsched->elements, element)) { + GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from scheduler", + GST_ELEMENT_NAME (element)); + + /* find what chain the element is in */ + chain = gst_fast_scheduler_find_chain (bsched, element); + + /* remove it from its chain */ + gst_fast_scheduler_chain_remove_element (chain, element); + + /* remove it from the list of elements */ + bsched->elements = g_list_remove (bsched->elements, element); + bsched->num_elements--; + + /* unset the scheduler pointer in the element */ + GST_ELEMENT_SCHED (element) = NULL; + } +} + +static GstElementStateReturn +gst_fast_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition) +{ + GstSchedulerChain *chain; + GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched); + + /* check if our parent changed state */ + if (GST_SCHEDULER_PARENT (sched) == element) { + GST_INFO (GST_CAT_SCHEDULING, "parent \"%s\" changed state", GST_ELEMENT_NAME (element)); + if (transition == GST_STATE_PLAYING_TO_PAUSED) { + GST_INFO (GST_CAT_SCHEDULING, "setting scheduler state to stopped"); + GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_STOPPED; + } + else if (transition == GST_STATE_PAUSED_TO_PLAYING) { + GST_INFO (GST_CAT_SCHEDULING, "setting scheduler state to running"); + GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_RUNNING; + } + else { + GST_INFO (GST_CAT_SCHEDULING, "no interesting state change, doing nothing"); + } + } + else if (transition == GST_STATE_PLAYING_TO_PAUSED || + transition == GST_STATE_PAUSED_TO_PLAYING) { + /* find the chain the element is in */ + chain = gst_fast_scheduler_find_chain (bsched, element); + + /* remove it from the chain */ + if (chain) { + if (transition == GST_STATE_PLAYING_TO_PAUSED) { + gst_fast_scheduler_chain_disable_element (chain, element); + } + else if (transition == GST_STATE_PAUSED_TO_PLAYING) { + if (!gst_fast_scheduler_chain_enable_element (chain, element)) { + GST_INFO (GST_CAT_SCHEDULING, "could not enable element \"%s\"", GST_ELEMENT_NAME (element)); + return GST_STATE_FAILURE; + } + } + } + else { + GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" not found in any chain, no state change", GST_ELEMENT_NAME (element)); + } + } + + return GST_STATE_SUCCESS; +} + +static void +gst_fast_scheduler_lock_element (GstScheduler * sched, GstElement * element) +{ + if (GST_ELEMENT_THREADSTATE (element)) + cothread_lock (GST_ELEMENT_THREADSTATE (element)); +} + +static void +gst_fast_scheduler_unlock_element (GstScheduler * sched, GstElement * element) +{ + if (GST_ELEMENT_THREADSTATE (element)) + cothread_unlock (GST_ELEMENT_THREADSTATE (element)); +} + +static void +gst_fast_scheduler_yield (GstScheduler *sched, GstElement *element) +{ + if (GST_ELEMENT_IS_COTHREAD_STOPPING (element)) { + cothread_switch (cothread_current_main ()); + } +} + +static gboolean +gst_fast_scheduler_interrupt (GstScheduler *sched, GstElement *element) +{ + if (cothread_current () != cothread_current_main()) { + cothread_switch (cothread_current_main ()); + return FALSE; + } + GST_FLAG_SET (element, GST_ELEMENT_INTERRUPTED); + return TRUE; +} + +static void +gst_fast_scheduler_error (GstScheduler *sched, GstElement *element) +{ + GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched); + GstSchedulerChain *chain; + + chain = gst_fast_scheduler_find_chain (bsched, element); + if (chain) + gst_fast_scheduler_chain_disable_element (chain, element); + + GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_ERROR; + + gst_fast_scheduler_interrupt (sched, element); +} + +static void +gst_fast_scheduler_pad_connect (GstScheduler * sched, GstPad *srcpad, GstPad *sinkpad) +{ + GstElement *srcelement, *sinkelement; + GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched); + + srcelement = GST_PAD_PARENT (srcpad); + g_return_if_fail (srcelement != NULL); + sinkelement = GST_PAD_PARENT (sinkpad); + g_return_if_fail (sinkelement != NULL); + + GST_INFO (GST_CAT_SCHEDULING, "have pad connected callback on %s:%s to %s:%s", + GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad)); + GST_DEBUG (GST_CAT_SCHEDULING, "srcpad sched is %p, sinkpad sched is %p\n", + GST_ELEMENT_SCHED (srcelement), GST_ELEMENT_SCHED (sinkelement)); + + if (GST_ELEMENT_SCHED (srcelement) == GST_ELEMENT_SCHED (sinkelement)) { + GST_INFO (GST_CAT_SCHEDULING, "peer %s:%s is in same scheduler, chaining together", + GST_DEBUG_PAD_NAME (sinkpad)); + gst_fast_scheduler_chain_elements (bsched, srcelement, sinkelement); + } +} + +static void +gst_fast_scheduler_pad_disconnect (GstScheduler * sched, GstPad * srcpad, GstPad * sinkpad) +{ + GstSchedulerChain *chain; + GstElement *element1, *element2; + GstSchedulerChain *chain1, *chain2; + GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched); + + GST_INFO (GST_CAT_SCHEDULING, "disconnecting pads %s:%s and %s:%s", + GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad)); + + /* we need to have the parent elements of each pad */ + element1 = GST_ELEMENT_CAST (GST_PAD_PARENT (srcpad)); + element2 = GST_ELEMENT_CAST (GST_PAD_PARENT (sinkpad)); + + /* first task is to remove the old chain they belonged to. + * this can be accomplished by taking either of the elements, + * since they are guaranteed to be in the same chain + * FIXME is it potentially better to make an attempt at splitting cleaner?? + */ + chain1 = gst_fast_scheduler_find_chain (bsched, element1); + chain2 = gst_fast_scheduler_find_chain (bsched, element2); + + if (chain1 != chain2) { + /* elements not in the same chain don't need to be separated */ + GST_INFO (GST_CAT_SCHEDULING, "elements not in the same chain"); + return; + } + + if (chain1) { + GST_INFO (GST_CAT_SCHEDULING, "destroying chain"); + gst_fast_scheduler_chain_destroy (chain1); + + /* now create a new chain to hold element1 and build it from scratch */ + chain1 = gst_fast_scheduler_chain_new (bsched); + gst_fast_scheduler_chain_recursive_add (chain1, element1); + } + + /* check the other element to see if it landed in the newly created chain */ + if (gst_fast_scheduler_find_chain (bsched, element2) == NULL) { + /* if not in chain, create chain and build from scratch */ + chain2 = gst_fast_scheduler_chain_new (bsched); + gst_fast_scheduler_chain_recursive_add (chain2, element2); + } +} + +static GstPad * +gst_fast_scheduler_pad_select (GstScheduler * sched, GList * padlist) +{ + GstPad *pad = NULL; + GList *padlist2 = padlist; + + GST_INFO (GST_CAT_SCHEDULING, "imlement me!!"); + + return pad; +} + +static GstSchedulerState +gst_fast_scheduler_iterate (GstScheduler * sched) +{ + GstBin *bin = GST_BIN (sched->parent); + GList *chains; + GstSchedulerChain *chain; + GstElement *entry; + GList *elements; + gint scheduled = 0; + GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched); + GstSchedulerState state; + + GST_DEBUG_ENTER ("(\"%s\")", GST_ELEMENT_NAME (bin)); + + /* step through all the chains */ + chains = bsched->chains; + + if (chains == NULL) { + GST_DEBUG (GST_CAT_DATAFLOW, "no chains!\n"); + + state = GST_SCHEDULER_STATE_STOPPED; + + goto exit; + } + + while (chains) { + chain = (GstSchedulerChain *) (chains->data); + chains = g_list_next (chains); + + if (chain->elements == NULL) { + continue; + } + + //if (chain->num_cothreaded > 1) { + if (FALSE) { + g_warning ("this scheduler can only deal with 1 cothreaded element in a chain"); + + state = GST_SCHEDULER_STATE_ERROR; + + goto exit; + } + else if (chain->num_cothreaded != 0) { + /* we just pick the first cothreaded element */ + GstElement *entry = GST_ELEMENT (chain->cothreaded_elements->data); + + GST_DEBUG (GST_CAT_DATAFLOW, "starting iteration via cothreads\n"); + + GST_FLAG_SET (entry, GST_ELEMENT_COTHREAD_STOPPING); + + GST_DEBUG (GST_CAT_DATAFLOW, "set COTHREAD_STOPPING flag on \"%s\"(@%p)\n", + GST_ELEMENT_NAME (entry), entry); + + if (GST_ELEMENT_THREADSTATE (entry)) { + cothread_switch (GST_ELEMENT_THREADSTATE (entry)); + } + else { + GST_DEBUG (GST_CAT_DATAFLOW, "cothread switch not possible, element has no threadstate\n"); + + GST_DEBUG (GST_CAT_DATAFLOW, "leaving (%s)\n", GST_ELEMENT_NAME (bin)); + + state = GST_SCHEDULER_STATE_ERROR; + + goto exit; + } + + GST_DEBUG (GST_CAT_SCHEDULING, "loopfunc of element %s ended\n", GST_ELEMENT_NAME (entry)); + + scheduled++; + } + else { + GstElement *entry = chain->entry; + if (entry) { + GList *pads = gst_element_get_pad_list (entry); + + GST_DEBUG (GST_CAT_DATAFLOW, "starting chained iteration\n"); + + while (pads) { + GstPad *pad = GST_PAD_CAST (pads->data); + pads = g_list_next (pads); + + if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) { + GstBuffer *buf; + + buf = GST_RPAD_GETFUNC (pad) (pad); + if (GST_ELEMENT_IS_INTERRUPTED (entry)) { + GST_FLAG_UNSET (entry, GST_ELEMENT_INTERRUPTED); + break; + } + gst_pad_push (pad, buf); + scheduled++; + } + } + } + else { + GST_INFO (GST_CAT_DATAFLOW, "no entry found!!"); + + state = GST_SCHEDULER_STATE_ERROR; + goto exit; + } + } + + state = GST_SCHEDULER_STATE (sched); + + if (state != GST_SCHEDULER_STATE_RUNNING) { + GST_INFO (GST_CAT_DATAFLOW, "scheduler is not running, in state %d", state); + + goto exit; + } + } + + GST_DEBUG (GST_CAT_DATAFLOW, "leaving (%s)\n", GST_ELEMENT_NAME (bin)); + + if (scheduled == 0) { + GST_INFO (GST_CAT_DATAFLOW, "nothing was scheduled, return STOPPED"); + state = GST_SCHEDULER_STATE_STOPPED; + } + else { + GST_INFO (GST_CAT_DATAFLOW, "scheduler still running, return RUNNING"); + state = GST_SCHEDULER_STATE_RUNNING; + } + +exit: + GST_DEBUG (GST_CAT_DATAFLOW, "leaving (%s) %d\n", GST_ELEMENT_NAME (bin), state); + + return state; +} + + +static void +gst_fast_scheduler_show (GstScheduler * sched) +{ + GList *chains, *elements; + GstElement *element; + GstSchedulerChain *chain; + GstFastScheduler *bsched = GST_FAST_SCHEDULER (sched); + + if (sched == NULL) { + g_print ("scheduler doesn't exist for this element\n"); + return; + } + + g_return_if_fail (GST_IS_SCHEDULER (sched)); + + g_print ("SCHEDULER DUMP FOR MANAGING BIN \"%s\"\n", GST_ELEMENT_NAME (sched->parent)); + + g_print ("scheduler has %d elements in it: ", bsched->num_elements); + elements = bsched->elements; + while (elements) { + element = GST_ELEMENT (elements->data); + elements = g_list_next (elements); + + g_print ("%s, ", GST_ELEMENT_NAME (element)); + } + g_print ("\n"); + + g_print ("scheduler has %d chains in it\n", bsched->num_chains); + chains = bsched->chains; + while (chains) { + chain = (GstSchedulerChain *) (chains->data); + chains = g_list_next (chains); + + g_print ("%p: ", chain); + + elements = chain->disabled; + while (elements) { + element = GST_ELEMENT (elements->data); + elements = g_list_next (elements); + + g_print ("!%s, ", GST_ELEMENT_NAME (element)); + } + + elements = chain->elements; + while (elements) { + element = GST_ELEMENT (elements->data); + elements = g_list_next (elements); + + g_print ("%s, ", GST_ELEMENT_NAME (element)); + } + g_print ("\n"); + } +} diff --git a/plugins/elements/gstfakesink.c b/plugins/elements/gstfakesink.c index c6d0198..21f4c92 100644 --- a/plugins/elements/gstfakesink.c +++ b/plugins/elements/gstfakesink.c @@ -46,6 +46,7 @@ enum { ARG_NUM_SINKS, ARG_SILENT, ARG_DUMP, + ARG_SYNC, ARG_LAST_MESSAGE, }; @@ -60,6 +61,7 @@ GST_PADTEMPLATE_FACTORY (fakesink_sink_factory, static void gst_fakesink_class_init (GstFakeSinkClass *klass); static void gst_fakesink_init (GstFakeSink *fakesink); +static void gst_fakesink_set_clock (GstElement *element, GstClock *clock); static GstPad* gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused); @@ -106,12 +108,14 @@ gst_fakesink_class_init (GstFakeSinkClass *klass) parent_class = g_type_class_ref (GST_TYPE_ELEMENT); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS, - g_param_spec_int ("num_sinks", "num_sinks", "num_sinks", + g_param_spec_int ("num_sinks", "Number of sinks", "The number of sinkpads", 1, G_MAXINT, 1, G_PARAM_READABLE)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE, g_param_spec_string ("last_message", "last_message", "last_message", NULL, G_PARAM_READABLE)); - + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SYNC, + g_param_spec_boolean("sync","Sync","Sync on the clock", + FALSE, G_PARAM_READWRITE)); /* CHECKME */ gst_element_class_install_std_props ( GST_ELEMENT_CLASS (klass), @@ -141,9 +145,22 @@ gst_fakesink_init (GstFakeSink *fakesink) fakesink->silent = FALSE; fakesink->dump = FALSE; + fakesink->sync = FALSE; fakesink->last_message = NULL; + + GST_ELEMENT (fakesink)->setclockfunc = gst_fakesink_set_clock; } +static void +gst_fakesink_set_clock (GstElement *element, GstClock *clock) +{ + GstFakeSink *sink; + + sink = GST_FAKESINK (element); + + sink->clock = clock; +} + static GstPad* gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused) { @@ -183,6 +200,9 @@ gst_fakesink_set_property (GObject *object, guint prop_id, const GValue *value, case ARG_DUMP: sink->dump = g_value_get_boolean (value); break; + case ARG_SYNC: + sink->sync = g_value_get_boolean (value); + break; default: break; } @@ -208,6 +228,9 @@ gst_fakesink_get_property (GObject *object, guint prop_id, GValue *value, GParam case ARG_DUMP: g_value_set_boolean (value, sink->dump); break; + case ARG_SYNC: + g_value_set_boolean (value, sink->sync); + break; case ARG_LAST_MESSAGE: g_value_set_string (value, sink->last_message); break; @@ -228,9 +251,12 @@ gst_fakesink_chain (GstPad *pad, GstBuffer *buf) fakesink = GST_FAKESINK (gst_pad_get_parent (pad)); + if (fakesink->sync) { + gst_element_clock_wait (GST_ELEMENT (fakesink), fakesink->clock, GST_BUFFER_TIMESTAMP (buf)); + } + if (!fakesink->silent) { - if (fakesink->last_message) - g_free (fakesink->last_message); + g_free (fakesink->last_message); fakesink->last_message = g_strdup_printf ("chain ******* (%s:%s)< (%d bytes, %lld) %p", GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf); diff --git a/plugins/elements/gstfakesink.h b/plugins/elements/gstfakesink.h index 4bc3bb5..6c38ae3 100644 --- a/plugins/elements/gstfakesink.h +++ b/plugins/elements/gstfakesink.h @@ -52,11 +52,14 @@ typedef struct _GstFakeSink GstFakeSink; typedef struct _GstFakeSinkClass GstFakeSinkClass; struct _GstFakeSink { - GstElement element; + GstElement element; - gboolean silent; - gboolean dump; - gchar *last_message; + gboolean silent; + gboolean dump; + gboolean sync; + GstClock *clock; + + gchar *last_message; }; struct _GstFakeSinkClass { diff --git a/plugins/elements/gstfakesrc.c b/plugins/elements/gstfakesrc.c index 18ef726..9686385 100644 --- a/plugins/elements/gstfakesrc.c +++ b/plugins/elements/gstfakesrc.c @@ -321,6 +321,7 @@ gst_fakesrc_event_handler (GstPad *pad, GstEvent *event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: src->buffer_count = GST_EVENT_SEEK_OFFSET (event); + if (!GST_EVENT_SEEK_FLUSH (event)) { gst_event_free (event); break; diff --git a/plugins/elements/gstfakesrc.h b/plugins/elements/gstfakesrc.h index 7f916ca..f4a0e67 100644 --- a/plugins/elements/gstfakesrc.h +++ b/plugins/elements/gstfakesrc.h @@ -105,7 +105,8 @@ struct _GstFakeSrc { gboolean silent; gboolean dump; gboolean need_flush; - gchar *last_message; + + gchar *last_message; }; struct _GstFakeSrcClass { diff --git a/plugins/elements/gstfilesrc.c b/plugins/elements/gstfilesrc.c index 3f97331..c50e8c5 100644 --- a/plugins/elements/gstfilesrc.c +++ b/plugins/elements/gstfilesrc.c @@ -78,7 +78,7 @@ GstElementDetails gst_filesrc_details = { "(C) 1999", }; -/*#define fs_print(format,args...) g_print(format, ## args)*/ +/*#define fs_print(format,args...) g_print(format, ## args) */ #define fs_print(format,args...) /* FileSrc signals and args */ @@ -549,7 +549,7 @@ gst_filesrc_get (GstPad *pad) /* we're done, return the buffer */ src->curoffset += GST_BUFFER_SIZE(buf); - g_object_notify (G_OBJECT (src), "offset"); + //g_object_notify (G_OBJECT (src), "offset"); return buf; } @@ -590,7 +590,7 @@ gst_filesrc_open_file (GstFileSrc *src) /* now notify of the changes */ g_object_freeze_notify (G_OBJECT (src)); g_object_notify (G_OBJECT (src), "filesize"); - g_object_notify (G_OBJECT (src), "offset"); + //g_object_notify (G_OBJECT (src), "offset"); g_object_thaw_notify (G_OBJECT (src)); GST_FLAG_SET (src, GST_FILESRC_OPEN); @@ -614,7 +614,7 @@ gst_filesrc_close_file (GstFileSrc *src) /* and notify that things changed */ g_object_freeze_notify (G_OBJECT (src)); g_object_notify (G_OBJECT (src), "filesize"); - g_object_notify (G_OBJECT (src), "offset"); + //g_object_notify (G_OBJECT (src), "offset"); g_object_thaw_notify (G_OBJECT (src)); if (src->mapbuf) diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c index 3540743..cf8ec85 100644 --- a/plugins/elements/gstqueue.c +++ b/plugins/elements/gstqueue.c @@ -83,7 +83,6 @@ static GstBuffer * gst_queue_get (GstPad *pad); static GstBufferPool* gst_queue_get_bufferpool (GstPad *pad); static void gst_queue_locked_flush (GstQueue *queue); -static void gst_queue_flush (GstQueue *queue); static GstElementStateReturn gst_queue_change_state (GstElement *element); @@ -275,15 +274,6 @@ gst_queue_locked_flush (GstQueue *queue) } static void -gst_queue_flush (GstQueue *queue) -{ - g_mutex_lock (queue->qlock); - gst_queue_locked_flush (queue); - g_mutex_unlock (queue->qlock); -} - - -static void gst_queue_chain (GstPad *pad, GstBuffer *buf) { GstQueue *queue; @@ -378,7 +368,7 @@ restart: return; } else { - gst_element_info (GST_ELEMENT (queue), "waiting for the app to restart source pad elements"); + g_print ("%s: waiting for the app to restart source pad elements\n", GST_ELEMENT_NAME (queue)); } } @@ -459,7 +449,7 @@ restart: goto restart; } else { - gst_element_info (GST_ELEMENT (queue), "waiting for the app to restart sink pad elements"); + g_print ("%s: waiting for the app to restart source pad elements\n", GST_ELEMENT_NAME (queue)); } } diff --git a/plugins/elements/gsttee.c b/plugins/elements/gsttee.c index ea38edc..2ea7428 100644 --- a/plugins/elements/gsttee.c +++ b/plugins/elements/gsttee.c @@ -181,7 +181,7 @@ gst_tee_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar GList *pads; g_return_val_if_fail (GST_IS_TEE (element), NULL); - + if (templ->direction != GST_PAD_SRC) { g_warning ("gsttee: request new pad that is not a SRC pad\n"); return NULL; -- 2.7.4