Added a first stab at a better clocking system.
authorWim Taymans <wim.taymans@gmail.com>
Sun, 3 Feb 2002 20:07:09 +0000 (20:07 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Sun, 3 Feb 2002 20:07:09 +0000 (20:07 +0000)
Original commit message from CVS:
Added a first stab at a better clocking system.
It still needs more infrastructure for async notification and custom clock
implementors.
This thing can still deadlock the pipeline.

15 files changed:
.gitmodules [new file with mode: 0644]
common [new submodule]
gst/Makefile.am
gst/autoplug/spidertest.c
gst/elements/gstdisksink.c
gst/gst.h
gst/gstbin.c
gst/gstbin.h
gst/gstclock.c
gst/gstclock.h
gst/gstelement.c
gst/gstelement.h
gst/gstsystemclock.c [new file with mode: 0644]
gst/gstsystemclock.h [new file with mode: 0644]
plugins/elements/gstdisksink.c

diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..1ba590b
--- /dev/null
@@ -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 (submodule)
index 0000000..d81417a
--- /dev/null
+++ b/common
@@ -0,0 +1 @@
+Subproject commit d81417a103945ab1c393e74557983b1163e9e353
index 549ddba158fc01782da040d0d3e841a4813ae60c..05e721ab627567036b528d427c4dce779eee3b0d 100644 (file)
@@ -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               \
index c5a25abc3f2571e23707320240ebc16ec4b4044b..8b97444ad9bf6e863d142069eddf693816d6c2d8 100644 (file)
@@ -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);
 
index 2d4e54fb07c46b00f57722cee08d264bb494ed4a..ffa27765bb21a9afa8ae11c031c10572651b9371 100644 (file)
@@ -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;
   }
 
index ff3e641331310a5335d2c34a836062fb0bb5a8be..9119ad0a7ac69996236d64cbe11608069f37817d 100644 (file)
--- a/gst/gst.h
+++ b/gst/gst.h
@@ -34,7 +34,7 @@
 #include <gst/gstpad.h>
 #include <gst/gstbuffer.h>
 #include <gst/gstcpu.h>
-#include <gst/gstclock.h>
+#include <gst/gstsystemclock.h>
 #include <gst/gstelement.h>
 #include <gst/gstbin.h>
 #include <gst/gstpipeline.h>
index c4282859bfb8b3ff631bc9cbb38acbfaa72be3fc..e63ae6849c49095bad0f78acff1b8b72bdf52914 100644 (file)
@@ -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;
index ddef90a959d7376beebf75f0f7ac7e4053a43a78..0df8ae18863cf05911cd49d1affde96534d37c68 100644 (file)
@@ -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 */
index 463171e28148de36ff31c59c95b746eb467b6772..fb1c2ff8ff794bc5a67efb6be885fdb42e8e401e 100644 (file)
 /* #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;
+
+  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 clock_type;
+}
 
-  clock->name = g_strdup (name);
-  clock->sinkobjects = NULL;
-  clock->sinkmutex = g_mutex_new ();
-  clock->lock = g_mutex_new ();
-  g_mutex_lock (clock->sinkmutex);
+static void
+gst_clock_class_init (GstClockClass *klass)
+{
+  GObjectClass *gobject_class;
+  GstObjectClass *gstobject_class;
 
-  clock->num = 0;
-  clock->num_locked = 0;
-  clock->locking = FALSE;
+  gobject_class = (GObjectClass*) klass;
+  gstobject_class = (GstObjectClass*) klass;
 
-  return clock;
+  parent_class = g_type_class_ref (GST_TYPE_OBJECT);
 }
 
-/**
- * gst_clock_get_system:
- *
- * Get the global system clock
- *
- * Returns: the global clock
- */
-GstClock*
-gst_clock_get_system(void)
+static void
+gst_clock_init (GstClock *clock)
 {
-  if (the_system_clock == NULL) {
-    the_system_clock = gst_clock_new ("system_clock");
-    gst_clock_reset (the_system_clock);
-  }
-  return the_system_clock;
+  clock->speed = 1.0;
+  clock->active = FALSE;
+  clock->start_time = 0;
+
+  clock->active_mutex = g_mutex_new ();
+  clock->active_cond = g_cond_new ();
 }
 
-/**
- * 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)
+gst_clock_reset (GstClock *clock)
 {
-  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++;
-  }
+  g_return_if_fail (GST_IS_CLOCK (clock));
+
+  clock->start_time = 0;
+  clock->active = FALSE;
+
+  if (CLASS (clock)->reset)
+    CLASS (clock)->reset (clock);
 }
 
-/**
- * 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)
+gst_clock_activate (GstClock *clock, gboolean active)
 {
-  struct timeval tfnow;
-  GstClockTime now;
-
-  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);
+  g_return_if_fail (GST_IS_CLOCK (clock));
+
+  clock->active = active;
+
+  if (CLASS (clock)->activate)
+    CLASS (clock)->activate (clock, active);
+
+  g_mutex_lock (clock->active_mutex);  
+  g_cond_signal (clock->active_cond);  
+  g_mutex_unlock (clock->active_mutex);        
+
 }
 
-/**
- * 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)
+gboolean
+gst_clock_is_active (GstClock *clock)
 {
-  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);
+  g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
 
-  return GST_CLOCK_DIFF (time, now);
+  return clock->active;
 }
 
-/**
- * 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)
+gst_clock_set_time (GstClock *clock, GstClockTime time)
 {
-  struct timeval tfnow;
-
-  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);
+  g_return_if_fail (GST_IS_CLOCK (clock));
+
+  if (CLASS (clock)->set_time)
+    CLASS (clock)->set_time (clock, time);
 }
 
-/**
- * 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)
+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)
 {
-  struct timeval tfnow;
-  GstClockTime now;
-  GstClockTimeDiff diff;
-
-
-  gettimeofday (&tfnow, (struct timezone *)NULL);
-  g_mutex_lock (clock->lock);
-  now = tfnow.tv_sec*1000000LL+tfnow.tv_usec - clock->start_time;
-
-  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_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);
+  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);      
   }
-  GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld done \n", 
-             GST_OBJECT_NAME (obj), time, now, diff);
+  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;
+}
+
index 8fc68c4d508431c8d1911d182e098d5fb1d7085c..08bdd131db19b3bb9dc0af1a423fc457a4f86de3 100644 (file)
 #ifndef __GST_CLOCK_H__
 #define __GST_CLOCK_H__
 
-#include <gst/gstobject.h>
-
-
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
+#include <gst/gstobject.h>
+
+#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;
 
-typedef guint64 GstClockTime;
-typedef gint64 GstClockTimeDiff;
+#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)
 
-#define GST_CLOCK_DIFF(s, e) (GstClockTimeDiff)((s)-(e))
+typedef struct _GstClock       GstClock;
+typedef struct _GstClockClass  GstClockClass;
 
-typedef struct _GstClock GstClock;
+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;
+
+  /* vtable */
+  void                         (*activate)             (GstClock *clock, gboolean active);
+  void                         (*reset)                (GstClock *clock);
+
+  void                         (*set_time)             (GstClock *clock, GstClockTime time);
+  GstClockTime                 (*get_time)             (GstClock *clock);
 
-void                   gst_clock_register              (GstClock *clock, GstObject *obj);
-void                   gst_clock_set                   (GstClock *clock, GstClockTime time);
+  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__ */
index a2dc9fc1f021799a8e6e752cf47c540ef8e22826..b2867217cb013a2b6300773e6d4e5e55e1d72e3c 100644 (file)
@@ -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);
index 302be82f397a33e691169b8ffbfb0914b1bc8714..62e62f1df68c571a472be4a7406a25deaa3dd788 100644 (file)
@@ -29,6 +29,7 @@
 #include <gst/gsttypes.h>
 #include <gst/gstobject.h>
 #include <gst/gstpad.h>
+#include <gst/gstclock.h>
 #include <gst/gstpluginfeature.h>
 
 #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 (file)
index 0000000..7693c4f
--- /dev/null
@@ -0,0 +1,199 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wim.taymans@chello.be>
+ *
+ * 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 <sys/time.h>
+
+/* #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 (file)
index 0000000..16c11b3
--- /dev/null
@@ -0,0 +1,68 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *
+ * 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 <gst/gstclock.h>
+
+#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__ */
index 2d4e54fb07c46b00f57722cee08d264bb494ed4a..ffa27765bb21a9afa8ae11c031c10572651b9371 100644 (file)
@@ -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;
   }