diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..1ba590b440 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "common"] + path = common + url = git://anongit.freedesktop.org/gstreamer/common diff --git a/common b/common new file mode 160000 index 0000000000..d81417a103 --- /dev/null +++ b/common @@ -0,0 +1 @@ +Subproject commit d81417a103945ab1c393e74557983b1163e9e353 diff --git a/gst/Makefile.am b/gst/Makefile.am index 549ddba158..05e721ab62 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -79,6 +79,7 @@ libgst_la_SOURCES = \ gstprops.c \ gstqueue.c \ gstscheduler.c \ + gstsystemclock.c \ gstthread.c \ $(GST_TRACE_SRC) \ gsttype.c \ @@ -187,6 +188,7 @@ libgstinclude_HEADERS = \ gstprops.h \ gstqueue.h \ gstscheduler.h \ + gstsystemclock.h \ gstthread.h \ gsttrace.h \ gsttype.h \ diff --git a/gst/autoplug/spidertest.c b/gst/autoplug/spidertest.c index c5a25abc3f..8b97444ad9 100644 --- a/gst/autoplug/spidertest.c +++ b/gst/autoplug/spidertest.c @@ -137,6 +137,8 @@ int main(int argc,char *argv[]) exit (-4); } + gst_bin_use_clock (GST_BIN (bin), gst_system_clock_obtain ()); + /* start playing */ gst_element_set_state(bin, GST_STATE_PLAYING); diff --git a/gst/elements/gstdisksink.c b/gst/elements/gstdisksink.c index 2d4e54fb07..ffa27765bb 100644 --- a/gst/elements/gstdisksink.c +++ b/gst/elements/gstdisksink.c @@ -304,7 +304,7 @@ gst_disksink_handle_event (GstPad *pad, GstEvent *event) gst_disksink_getcurrentfilename(disksink), sys_errlist[errno]); break; default: - g_warning("Unhandled event %d\n", type); + gst_pad_event_default (pad, event); break; } diff --git a/gst/gst.h b/gst/gst.h index ff3e641331..9119ad0a7a 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/gst/gstbin.c b/gst/gstbin.c index c4282859bf..e63ae6849c 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -25,6 +25,8 @@ #include "gstevent.h" #include "gstbin.h" +#include "gstxml.h" +#include "gstsystemclock.h" #include "gstscheduler.h" @@ -160,6 +162,93 @@ gst_bin_reset_element_sched (GstElement * element, GstScheduler * sched) 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\n", 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; + GstElement *provider; + 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\n"); + 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); +} + +void +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; +} + +void +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; +} + static void gst_bin_set_element_sched (GstElement * element, GstScheduler * sched) { @@ -412,14 +501,9 @@ gst_bin_child_state_change (GstBin *bin, GstElementState oldstate, GstElementSta void gst_bin_child_error (GstBin *bin, GstElement *child) { + g_return_if_fail (GST_IS_BIN (bin)); + if (GST_STATE (bin) != GST_STATE_NULL) { - /* - GST_STATE_PENDING (bin) = ((GST_STATE (bin) >> 1)); - if (gst_element_set_state (bin, GST_STATE (bin)>>1) != GST_STATE_SUCCESS) { - gst_element_error (GST_ELEMENT (bin), "bin \"%s\" couldn't change state on error from child \"%s\"", - GST_ELEMENT_NAME (bin), GST_ELEMENT_NAME (child)); - } - */ gst_element_info (GST_ELEMENT (bin), "bin \"%s\" stopped because child \"%s\" signalled an error", GST_ELEMENT_NAME (bin), GST_ELEMENT_NAME (child)); } @@ -443,6 +527,7 @@ gst_bin_change_state (GstElement * element) GstElement *child; GstElementStateReturn ret; GstElementState old_state, pending; + gint transition; gboolean have_async = FALSE; g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE); @@ -451,6 +536,7 @@ gst_bin_change_state (GstElement * element) old_state = GST_STATE (element); pending = GST_STATE_PENDING (element); + transition = GST_STATE_TRANSITION (element); GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing childrens' state from %s to %s", gst_element_statename (old_state), gst_element_statename (pending)); @@ -482,6 +568,28 @@ 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), @@ -499,9 +607,13 @@ gst_bin_change_state (GstElement * element) static GstElementStateReturn gst_bin_change_state_norecurse (GstBin * bin) { + GstElementStateReturn ret; + if (GST_ELEMENT_CLASS (parent_class)->change_state) { GST_DEBUG_ELEMENT (GST_CAT_STATES, bin, "setting bin's own state\n"); - return GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (bin)); + ret = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (bin)); + + return ret; } else return GST_STATE_FAILURE; diff --git a/gst/gstbin.h b/gst/gstbin.h index ddef90a959..0df8ae1886 100644 --- a/gst/gstbin.h +++ b/gst/gstbin.h @@ -48,6 +48,10 @@ 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, @@ -57,6 +61,8 @@ typedef enum { /* we prefer to have cothreads when its an option, over chain-based */ GST_BIN_FLAG_PREFER_COTHREADS, + GST_BIN_FLAG_FIXED_CLOCK, + /* padding */ GST_BIN_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 4, } GstBinFlags; @@ -65,15 +71,17 @@ typedef enum { /*typedef struct _GstBinClass GstBinClass; */ struct _GstBin { - GstElement element; + GstElement element; /* our children */ - gint numchildren; - GList *children; + gint numchildren; + GList *children; GstElementState child_states[GST_NUM_STATES]; + + GstClock *clock; - gpointer sched_private; + gpointer sched_private; }; struct _GstBinClass { @@ -108,11 +116,18 @@ gboolean gst_bin_set_state_type (GstBin *bin, GstElementState state, GType type gboolean gst_bin_iterate (GstBin *bin); +void gst_bin_use_clock (GstBin *bin, GstClock *clock); +GstClock* gst_bin_get_clock (GstBin *bin); +void gst_bin_auto_clock (GstBin *bin); + /* internal */ +/* 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 } #endif /* __cplusplus */ diff --git a/gst/gstclock.c b/gst/gstclock.c index 463171e281..fb1c2ff8ff 100644 --- a/gst/gstclock.c +++ b/gst/gstclock.c @@ -25,176 +25,153 @@ /* #define GST_DEBUG_ENABLED */ #include "gst_private.h" -#include "gstelement.h" #include "gstclock.h" +#define CLASS(clock) GST_CLOCK_CLASS (G_OBJECT_GET_CLASS (clock)) -static GstClock *the_system_clock = NULL; -/** - * gst_clock_new: - * @name: the name of the new clock - * - * create a new clock element - * - * Returns: the new clock element - */ -GstClock* -gst_clock_new (gchar *name) +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 }; */ + +GType +gst_clock_get_type (void) { - GstClock *clock = (GstClock *) g_malloc(sizeof(GstClock)); + static GType clock_type = 0; - clock->name = g_strdup (name); - clock->sinkobjects = NULL; - clock->sinkmutex = g_mutex_new (); - clock->lock = g_mutex_new (); - g_mutex_lock (clock->sinkmutex); - - clock->num = 0; - clock->num_locked = 0; - clock->locking = FALSE; - - return clock; -} - -/** - * gst_clock_get_system: - * - * Get the global system clock - * - * Returns: the global clock - */ -GstClock* -gst_clock_get_system(void) -{ - if (the_system_clock == NULL) { - the_system_clock = gst_clock_new ("system_clock"); - gst_clock_reset (the_system_clock); + if (!clock_type) { + static const GTypeInfo clock_info = { + sizeof (GstObjectClass), + NULL, + NULL, + (GClassInitFunc) gst_clock_class_init, + NULL, + NULL, + sizeof (GstObject), + 4, + (GInstanceInitFunc) gst_clock_init, + NULL + }; + clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock", + &clock_info, G_TYPE_FLAG_ABSTRACT); } - return the_system_clock; + return clock_type; } -/** - * gst_clock_register: - * @clock: the name of the clock to register to - * @obj: the object registering to the clock - * - * State that an object is interested in listening to the - * given clock - */ -void -gst_clock_register (GstClock *clock, GstObject *obj) +static void +gst_clock_class_init (GstClockClass *klass) { - if ((GST_ELEMENT(obj))->numsrcpads == 0) { - GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting registered sink object 0x%p\n", obj); - clock->sinkobjects = g_list_append (clock->sinkobjects, obj); - clock->num++; - } + GObjectClass *gobject_class; + GstObjectClass *gstobject_class; + + gobject_class = (GObjectClass*) klass; + gstobject_class = (GstObjectClass*) klass; + + parent_class = g_type_class_ref (GST_TYPE_OBJECT); } -/** - * gst_clock_set: - * @clock: The clock to set - * @time: the time to set - * - * Set the time of the given clock to time. - */ -void -gst_clock_set (GstClock *clock, GstClockTime time) +static void +gst_clock_init (GstClock *clock) { - struct timeval tfnow; - GstClockTime now; + clock->speed = 1.0; + clock->active = FALSE; + clock->start_time = 0; - gettimeofday (&tfnow, (struct timezone *)NULL); - now = tfnow.tv_sec*1000000LL+tfnow.tv_usec; - g_mutex_lock (clock->lock); - clock->start_time = now - time; - g_mutex_unlock (clock->lock); - GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting clock to %llu %llu %llu\n", - time, now, clock->start_time); + clock->active_mutex = g_mutex_new (); + clock->active_cond = g_cond_new (); } -/** - * gst_clock_current_diff: - * @clock: the clock to calculate the diff against - * @time: the time - * - * Calculate the difference between the given clock and the - * given time - * - * Returns: the clock difference - */ -GstClockTimeDiff -gst_clock_current_diff (GstClock *clock, GstClockTime time) -{ - struct timeval tfnow; - GstClockTime now; - - gettimeofday (&tfnow, (struct timezone *)NULL); - g_mutex_lock (clock->lock); - now = ((guint64)tfnow.tv_sec*1000000LL+tfnow.tv_usec) - (guint64)clock->start_time; - g_mutex_unlock (clock->lock); - - return GST_CLOCK_DIFF (time, now); -} - -/** - * gst_clock_reset: - * @clock: the clock to reset - * - * Reset the given clock. The of the clock will be adjusted back - * to 0. - */ void gst_clock_reset (GstClock *clock) { - struct timeval tfnow; + g_return_if_fail (GST_IS_CLOCK (clock)); - gettimeofday (&tfnow, (struct timezone *)NULL); - g_mutex_lock (clock->lock); - clock->start_time = ((guint64)tfnow.tv_sec)*1000000LL+tfnow.tv_usec; - clock->current_time = clock->start_time; - clock->adjust = 0LL; - GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting start clock %llu\n", clock->start_time); - g_mutex_unlock (clock->lock); + clock->start_time = 0; + clock->active = FALSE; + + if (CLASS (clock)->reset) + CLASS (clock)->reset (clock); } -/** - * gst_clock_wait: - * @clock: the clock to wait on - * @time: the time to wait for - * @obj: the object performing the wait - * - * Wait for a specific clock tick on the given clock. - */ void -gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj) +gst_clock_activate (GstClock *clock, gboolean active) { - struct timeval tfnow; - GstClockTime now; - GstClockTimeDiff diff; + g_return_if_fail (GST_IS_CLOCK (clock)); + clock->active = active; - gettimeofday (&tfnow, (struct timezone *)NULL); - g_mutex_lock (clock->lock); - now = tfnow.tv_sec*1000000LL+tfnow.tv_usec - clock->start_time; + if (CLASS (clock)->activate) + CLASS (clock)->activate (clock, active); - diff = GST_CLOCK_DIFF (time, now); - /* if we are not behind wait a bit */ - GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld\n", - GST_OBJECT_NAME (obj), time, now, diff); + g_mutex_lock (clock->active_mutex); + g_cond_signal (clock->active_cond); + g_mutex_unlock (clock->active_mutex); - g_mutex_unlock (clock->lock); - if (diff > 10000 ) { - tfnow.tv_usec = (diff % 1000000); - tfnow.tv_sec = diff / 1000000; - /* FIXME, this piece of code does not work with egcs optimisations on, had to use the following line */ - if (!tfnow.tv_sec) { - select(0, NULL, NULL, NULL, &tfnow); - } - else GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting %u %llu %llu %llu seconds\n", - GST_OBJECT_NAME (obj), (int)tfnow.tv_sec, now, diff, time); - } - GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld done \n", - GST_OBJECT_NAME (obj), time, now, diff); } + +gboolean +gst_clock_is_active (GstClock *clock) +{ + g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE); + + 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) +{ + g_return_val_if_fail (GST_IS_CLOCK (clock), 0LL); + + if (CLASS (clock)->get_time) + return CLASS (clock)->get_time (clock); + + return 0LL; +} + +GstClockReturn +gst_clock_wait (GstClock *clock, GstClockTime time) +{ + g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_STOPPED); + + 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; +} + +void +gst_clock_set_resolution (GstClock *clock, guint64 resolution) +{ + g_return_if_fail (GST_IS_CLOCK (clock)); + + if (CLASS (clock)->set_resolution) + CLASS (clock)->set_resolution (clock, resolution); +} + +guint64 +gst_clock_get_resolution (GstClock *clock) +{ + g_return_val_if_fail (GST_IS_CLOCK (clock), 0LL); + + if (CLASS (clock)->get_resolution) + return CLASS (clock)->get_resolution (clock); + + return 0LL; +} + diff --git a/gst/gstclock.h b/gst/gstclock.h index 8fc68c4d50..08bdd131db 100644 --- a/gst/gstclock.h +++ b/gst/gstclock.h @@ -24,45 +24,103 @@ #ifndef __GST_CLOCK_H__ #define __GST_CLOCK_H__ -#include - - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +#include -typedef guint64 GstClockTime; -typedef gint64 GstClockTimeDiff; +#define GST_TYPE_CLOCK \ + (gst_clock_get_type()) +#define GST_CLOCK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLOCK,GstClock)) +#define GST_CLOCK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLOCK,GstClockClass)) +#define GST_IS_CLOCK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLOCK)) +#define GST_IS_CLOCK_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLOCK)) + +typedef guint64 GstClockTime; +typedef gint64 GstClockTimeDiff; +typedef gpointer GstClockID; -#define GST_CLOCK_DIFF(s, e) (GstClockTimeDiff)((s)-(e)) +#define GST_CLOCK_DIFF(s, e) (GstClockTimeDiff)((s)-(e)) +#define GST_TIMEVAL_TO_TIME(tv) ((tv).tv_sec * (guint64) G_USEC_PER_SEC + (tv).tv_usec) -typedef struct _GstClock GstClock; +typedef struct _GstClock GstClock; +typedef struct _GstClockClass GstClockClass; + +typedef void (*GstClockCallback) (GstClock *clock, GstClockTime time, GstClockID id, gpointer user_data); + +typedef enum +{ + GST_CLOCK_STOPPED = 0, + GST_CLOCK_TIMEOUT = 1, + GST_CLOCK_EARLY = 2, + GST_CLOCK_ERROR = 3, +} GstClockReturn; struct _GstClock { - gchar *name; - GstClockTime start_time; - GstClockTime current_time; - GstClockTimeDiff adjust; - gboolean locking; - GList *sinkobjects; - gint num, num_locked; - GMutex *sinkmutex; - GMutex *lock; + GstObject object; + + GstClockTime start_time; + gdouble speed; + gboolean active; + + GMutex *active_mutex; + GCond *active_cond; }; -GstClock* gst_clock_new (gchar *name); -GstClock* gst_clock_get_system (void); +struct _GstClockClass { + GstObjectClass parent_class; -void gst_clock_register (GstClock *clock, GstObject *obj); -void gst_clock_set (GstClock *clock, GstClockTime time); + /* 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); + + void (*set_resolution) (GstClock *clock, guint64 resolution); + guint64 (*get_resolution) (GstClock *clock); + + /* signals */ +}; + +GType gst_clock_get_type (void); + +void gst_clock_set_speed (GstClock *clock, gdouble speed); +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); -void gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj); -GstClockTimeDiff gst_clock_current_diff (GstClock *clock, GstClockTime time); + +void gst_clock_set_time (GstClock *clock, GstClockTime time); +GstClockTime gst_clock_get_time (GstClock *clock); + +GstClockReturn gst_clock_wait (GstClock *clock, GstClockTime time); +GstClockID gst_clock_wait_async (GstClock *clock, GstClockTime time, + GstClockCallback func, gpointer user_data); +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); + +void gst_clock_set_resolution (GstClock *clock, guint64 resolution); +guint64 gst_clock_get_resolution (GstClock *clock); #ifdef __cplusplus } #endif /* __cplusplus */ - #endif /* __GST_CLOCK_H__ */ diff --git a/gst/gstelement.c b/gst/gstelement.c index a2dc9fc1f0..b2867217cb 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -187,7 +187,7 @@ gst_element_set_property (GObject *object, guint prop_id, const GValue *value, G GstElementClass *oclass = CLASS (object); if (oclass->set_property) - (oclass->set_property)(object,prop_id,value,pspec); + (oclass->set_property) (object, prop_id, value, pspec); } @@ -197,7 +197,7 @@ gst_element_get_property (GObject *object, guint prop_id, GValue *value, GParamS GstElementClass *oclass = CLASS (object); if (oclass->get_property) - (oclass->get_property)(object,prop_id,value,pspec); + (oclass->get_property) (object, prop_id, value, pspec); } @@ -273,6 +273,61 @@ gst_element_get_parent (GstElement *element) return GST_OBJECT_PARENT (element); } +/** + * gst_element_set_clock: + * @element: GstElement to set the clock to + * @clock: the clock to set for the element + * + * Set the clock for the element + */ +void +gst_element_set_clock (GstElement *element, GstClock *clock) +{ + GstElementClass *oclass; + + g_return_if_fail (element != NULL); + g_return_if_fail (GST_IS_ELEMENT (element)); + + if (element->setclockfunc) + element->setclockfunc (element, clock); +} + +/** + * gst_element_get_clock: + * @element: GstElement to get the clock of + * + * Get the clock of the element + */ +GstClock* +gst_element_get_clock (GstElement *element) +{ + g_return_val_if_fail (element != NULL, NULL); + g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); + + if (element->getclockfunc) + return element->getclockfunc (element); + + return NULL; +} + +/** + * gst_element_clock_wait: + * @element: GstElement to wait for the clock + * @clock: the clock to wait for + * @time: the time to wait for + * + * Wait for a specific time on the clock + */ +GstClockReturn +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); +} + /** * gst_element_add_pad: * @element: element to add pad to @@ -328,11 +383,11 @@ gst_element_remove_pad (GstElement *element, GstPad *pad) g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (GST_PAD_PARENT (pad) == element); + /* check to see if the pad is still connected */ /* FIXME: what if someone calls _remove_pad instead of - _remove_ghost_pad? */ - if (GST_IS_REAL_PAD (pad)) - { + _remove_ghost_pad? */ + if (GST_IS_REAL_PAD (pad)) { g_return_if_fail (GST_RPAD_PEER (pad) == NULL); } @@ -1364,12 +1419,14 @@ gst_element_dispose (GObject *object) orig = pads = g_list_copy (element->pads); while (pads) { pad = GST_PAD (pads->data); - if (GST_PAD_PEER (pad)) - { - GST_DEBUG (GST_CAT_REFCOUNTING, "disconnecting pad '%s'\n",GST_OBJECT_NAME(GST_OBJECT (GST_PAD (GST_PAD_PEER (pad))))); + + if (GST_PAD_PEER (pad)) { + GST_DEBUG (GST_CAT_REFCOUNTING, "disconnecting pad '%s'\n", + GST_OBJECT_NAME (GST_OBJECT (GST_PAD (GST_PAD_PEER (pad))))); gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad))); } gst_element_remove_pad (element, pad); + pads = g_list_next (pads); } g_list_free (orig); diff --git a/gst/gstelement.h b/gst/gstelement.h index 302be82f39..62e62f1df6 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -108,6 +109,7 @@ typedef enum { #define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj)) #define GST_ELEMENT_MANAGER(obj) (((GstElement*)(obj))->manager) #define GST_ELEMENT_SCHED(obj) (((GstElement*)(obj))->sched) +#define GST_ELEMENT_CLOCK(obj) (((GstElement*)(obj))->clock) #define GST_ELEMENT_PADS(obj) ((obj)->pads) /*typedef struct _GstElement GstElement;*/ @@ -115,7 +117,9 @@ typedef enum { typedef struct _GstElementFactory GstElementFactory; typedef struct _GstElementFactoryClass GstElementFactoryClass; -typedef void (*GstElementLoopFunction) (GstElement *element); +typedef void (*GstElementLoopFunction) (GstElement *element); +typedef void (*GstElementSetClockFunction) (GstElement *element, GstClock *clock); +typedef GstClock* (*GstElementGetClockFunction) (GstElement *element); struct _GstElement { GstObject object; @@ -128,6 +132,8 @@ struct _GstElement { GstScheduler *sched; gpointer sched_private; + GstElementSetClockFunction setclockfunc; + GstElementGetClockFunction getclockfunc; /* element pads */ guint16 numpads; @@ -183,6 +189,10 @@ const gchar* gst_element_get_name (GstElement *element); void gst_element_set_parent (GstElement *element, GstObject *parent); GstObject* gst_element_get_parent (GstElement *element); +GstClock* gst_element_get_clock (GstElement *element); +void gst_element_set_clock (GstElement *element, GstClock *clock); +GstClockReturn gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time); + void gst_element_yield (GstElement *element); gboolean gst_element_interrupt (GstElement *element); void gst_element_set_sched (GstElement *element, GstScheduler *sched); diff --git a/gst/gstsystemclock.c b/gst/gstsystemclock.c new file mode 100644 index 0000000000..7693c4fe7c --- /dev/null +++ b/gst/gstsystemclock.c @@ -0,0 +1,199 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstclock.c: Clock subsystem for maintaining time sync + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +/* #define GST_DEBUG_ENABLED */ +#include "gst_private.h" + +#include "gstsystemclock.h" + +#define CLASS(clock) GST_SYSTEM_CLOCK_CLASS (G_OBJECT_GET_CLASS (clock)) + +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 guint64 gst_system_clock_get_resolution (GstClock *clock); + + +static GstClockClass *parent_class = NULL; +/* static guint gst_system_clock_signals[LAST_SIGNAL] = { 0 }; */ + +GType +gst_system_clock_get_type (void) +{ + static GType clock_type = 0; + + if (!clock_type) { + static const GTypeInfo clock_info = { + sizeof (GstSystemClockClass), + NULL, + NULL, + (GClassInitFunc) gst_system_clock_class_init, + NULL, + NULL, + sizeof (GstSystemClock), + 4, + (GInstanceInitFunc) gst_system_clock_init, + NULL + }; + clock_type = g_type_register_static (GST_TYPE_CLOCK, "GstSystemClock", + &clock_info, 0); + } + return clock_type; +} + +static void +gst_system_clock_class_init (GstSystemClockClass *klass) +{ + GObjectClass *gobject_class; + GstObjectClass *gstobject_class; + GstClockClass *gstclock_class; + + gobject_class = (GObjectClass*) klass; + gstobject_class = (GstObjectClass*) klass; + gstclock_class = (GstClockClass*) 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_resolution = gst_system_clock_get_resolution; +} + +static void +gst_system_clock_init (GstSystemClock *clock) +{ +} + +GstClock* +gst_system_clock_obtain (void) +{ + if (_the_system_clock == NULL) { + _the_system_clock = GST_CLOCK (g_object_new (GST_TYPE_SYSTEM_CLOCK, NULL)); + gst_object_set_name (GST_OBJECT (_the_system_clock), "GstSystemClock"); + } + 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) +{ + 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; +} + +static guint64 +gst_system_clock_get_resolution (GstClock *clock) +{ + return 1; +} + + diff --git a/gst/gstsystemclock.h b/gst/gstsystemclock.h new file mode 100644 index 0000000000..16c11b3abb --- /dev/null +++ b/gst/gstsystemclock.h @@ -0,0 +1,68 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstclock.h: Header for clock 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_SYSTEM_CLOCK_H__ +#define __GST_SYSTEM_CLOCK_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GST_TYPE_SYSTEM_CLOCK \ + (gst_system_clock_get_type()) +#define GST_SYSTEM_CLOCK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SYSTEM_CLOCK,GstSystemClock)) +#define GST_SYSTEM_CLOCK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SYSTEM_CLOCK,GstSystemClockClass)) +#define GST_IS_SYSTEM_CLOCK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SYSTEM_CLOCK)) +#define GST_IS_SYSTEM_CLOCK_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SYSTEM_CLOCK)) + + +typedef struct _GstSystemClock GstSystemClock; +typedef struct _GstSystemClockClass GstSystemClockClass; + +struct _GstSystemClock { + GstClock clock; + + GstClockTime absolute_start; + GstClockTime current_time; +}; + +struct _GstSystemClockClass { + GstClockClass parent_class; +}; + +GType gst_system_clock_get_type (void); + +GstClock* gst_system_clock_obtain (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_SYSTEM_CLOCK_H__ */ diff --git a/plugins/elements/gstdisksink.c b/plugins/elements/gstdisksink.c index 2d4e54fb07..ffa27765bb 100644 --- a/plugins/elements/gstdisksink.c +++ b/plugins/elements/gstdisksink.c @@ -304,7 +304,7 @@ gst_disksink_handle_event (GstPad *pad, GstEvent *event) gst_disksink_getcurrentfilename(disksink), sys_errlist[errno]); break; default: - g_warning("Unhandled event %d\n", type); + gst_pad_event_default (pad, event); break; }