aggregator: Assert if the sink/src pad type that is to be used is not a GstAggregator...
[platform/upstream/gstreamer.git] / gst / gstclock.c
index e17d232..279b1f8 100644 (file)
@@ -23,6 +23,7 @@
 
 /**
  * SECTION:gstclock
+ * @title: GstClock
  * @short_description: Abstract class for global clocks
  * @see_also: #GstSystemClock, #GstPipeline
  *
@@ -74,7 +75,7 @@
  * for unreffing the ids itself. This holds for both periodic and single shot
  * notifications. The reason being that the owner of the #GstClockID has to
  * keep a handle to the #GstClockID to unblock the wait on FLUSHING events or
- * state changes and if the entry would be unreffed automatically, the handle 
+ * state changes and if the entry would be unreffed automatically, the handle
  * might become invalid without any notification.
  *
  * These clock operations do not operate on the running time, so the callbacks
@@ -90,7 +91,7 @@
  * plugins that have an internal clock but must operate with another clock
  * selected by the #GstPipeline.  They can track the offset and rate difference
  * of their internal clock relative to the master clock by using the
- * gst_clock_get_calibration() function. 
+ * gst_clock_get_calibration() function.
  *
  * The master/slave synchronisation can be tuned with the #GstClock:timeout,
  * #GstClock:window-size and #GstClock:window-threshold properties.
@@ -166,6 +167,14 @@ struct _GstClockPrivate
   gboolean synced;
 };
 
+typedef struct
+{
+  GstClockEntry entry;
+  GWeakRef clock;
+} GstClockEntryImpl;
+
+#define GST_CLOCK_ENTRY_CLOCK_WEAK_REF(entry) (&((GstClockEntryImpl *)(entry))->clock)
+
 /* seqlocks */
 #define read_seqbegin(clock)                                   \
   g_atomic_int_get (&clock->priv->post_count);
@@ -240,7 +249,7 @@ gst_clock_entry_new (GstClock * clock, GstClockTime time,
 {
   GstClockEntry *entry;
 
-  entry = g_slice_new (GstClockEntry);
+  entry = (GstClockEntry *) g_slice_new (GstClockEntryImpl);
 
   /* FIXME: add tracer hook for struct allocations such as clock entries */
 
@@ -248,7 +257,14 @@ gst_clock_entry_new (GstClock * clock, GstClockTime time,
       "created entry %p, time %" GST_TIME_FORMAT, entry, GST_TIME_ARGS (time));
 
   entry->refcount = 1;
+#ifndef GST_REMOVE_DEPRECATED
+#ifndef GST_DISABLE_DEPRECATED
   entry->clock = clock;
+#else
+  entry->_clock = clock;
+#endif
+#endif
+  g_weak_ref_init (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry), clock);
   entry->type = type;
   entry->time = time;
   entry->interval = interval;
@@ -269,7 +285,8 @@ gst_clock_entry_reinit (GstClock * clock, GstClockEntry * entry,
     GstClockTime time, GstClockTime interval, GstClockEntryType type)
 {
   g_return_val_if_fail (entry->status != GST_CLOCK_BUSY, FALSE);
-  g_return_val_if_fail (entry->clock == clock, FALSE);
+  g_return_val_if_fail (gst_clock_id_uses_clock ((GstClockID) entry, clock),
+      FALSE);
 
   entry->type = type;
   entry->time = time;
@@ -353,9 +370,11 @@ _gst_clock_id_free (GstClockID id)
   if (entry->destroy_data)
     entry->destroy_data (entry->user_data);
 
+  g_weak_ref_clear (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry));
+
   /* FIXME: add tracer hook for struct allocations such as clock entries */
 
-  g_slice_free (GstClockEntry, id);
+  g_slice_free (GstClockEntryImpl, (GstClockEntryImpl *) id);
 }
 
 /**
@@ -490,23 +509,23 @@ gst_clock_id_get_time (GstClockID id)
  * @jitter: (out) (allow-none): a pointer that will contain the jitter,
  *     can be %NULL.
  *
- * Perform a blocking wait on @id. 
+ * Perform a blocking wait on @id.
  * @id should have been created with gst_clock_new_single_shot_id()
  * or gst_clock_new_periodic_id() and should not have been unscheduled
- * with a call to gst_clock_id_unschedule(). 
+ * with a call to gst_clock_id_unschedule().
  *
  * If the @jitter argument is not %NULL and this function returns #GST_CLOCK_OK
  * or #GST_CLOCK_EARLY, it will contain the difference
  * against the clock and the time of @id when this method was
- * called. 
+ * called.
  * Positive values indicate how late @id was relative to the clock
- * (in which case this function will return #GST_CLOCK_EARLY). 
- * Negative values indicate how much time was spent waiting on the clock 
+ * (in which case this function will return #GST_CLOCK_EARLY).
+ * Negative values indicate how much time was spent waiting on the clock
  * before this function returned.
  *
  * Returns: the result of the blocking wait. #GST_CLOCK_EARLY will be returned
- * if the current clock time is past the time of @id, #GST_CLOCK_OK if 
- * @id was scheduled in time. #GST_CLOCK_UNSCHEDULED if @id was 
+ * if the current clock time is past the time of @id, #GST_CLOCK_OK if
+ * @id was scheduled in time. #GST_CLOCK_UNSCHEDULED if @id was
  * unscheduled with gst_clock_id_unschedule().
  *
  * MT safe.
@@ -525,7 +544,9 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
   entry = (GstClockEntry *) id;
   requested = GST_CLOCK_ENTRY_TIME (entry);
 
-  clock = GST_CLOCK_ENTRY_CLOCK (entry);
+  clock = g_weak_ref_get (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry));
+  if (G_UNLIKELY (clock == NULL))
+    goto invalid_entry;
 
   /* can't sync on invalid times */
   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
@@ -548,6 +569,7 @@ gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
   if (entry->type == GST_CLOCK_ENTRY_PERIODIC)
     entry->time = requested + entry->interval;
 
+  gst_object_unref (clock);
   return res;
 
   /* ERRORS */
@@ -555,13 +577,20 @@ invalid_time:
   {
     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
         "invalid time requested, returning _BADTIME");
+    gst_object_unref (clock);
     return GST_CLOCK_BADTIME;
   }
 not_supported:
   {
     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported");
+    gst_object_unref (clock);
     return GST_CLOCK_UNSUPPORTED;
   }
+invalid_entry:
+  {
+    GST_CAT_DEBUG (GST_CAT_CLOCK, "clock entry %p lost its clock", id);
+    return GST_CLOCK_ERROR;
+  }
 }
 
 /**
@@ -599,7 +628,9 @@ gst_clock_id_wait_async (GstClockID id,
 
   entry = (GstClockEntry *) id;
   requested = GST_CLOCK_ENTRY_TIME (entry);
-  clock = GST_CLOCK_ENTRY_CLOCK (entry);
+  clock = g_weak_ref_get (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry));
+  if (G_UNLIKELY (clock == NULL))
+    goto invalid_entry;
 
   /* can't sync on invalid times */
   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
@@ -616,6 +647,7 @@ gst_clock_id_wait_async (GstClockID id,
 
   res = cclass->wait_async (clock, entry);
 
+  gst_object_unref (clock);
   return res;
 
   /* ERRORS */
@@ -624,13 +656,20 @@ invalid_time:
     (func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
         "invalid time requested, returning _BADTIME");
+    gst_object_unref (clock);
     return GST_CLOCK_BADTIME;
   }
 not_supported:
   {
     GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported");
+    gst_object_unref (clock);
     return GST_CLOCK_UNSUPPORTED;
   }
+invalid_entry:
+  {
+    GST_CAT_DEBUG (GST_CAT_CLOCK, "clock entry %p lost its clock", id);
+    return GST_CLOCK_ERROR;
+  }
 }
 
 /**
@@ -654,12 +693,23 @@ gst_clock_id_unschedule (GstClockID id)
   g_return_if_fail (id != NULL);
 
   entry = (GstClockEntry *) id;
-  clock = entry->clock;
+  clock = g_weak_ref_get (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry));
+  if (G_UNLIKELY (clock == NULL))
+    goto invalid_entry;
 
   cclass = GST_CLOCK_GET_CLASS (clock);
 
   if (G_LIKELY (cclass->unschedule))
     cclass->unschedule (clock, entry);
+
+  gst_object_unref (clock);
+  return;
+
+invalid_entry:
+  {
+    GST_CAT_DEBUG (GST_CAT_CLOCK, "clock entry %p lost its clock", id);
+    return;
+  }
 }
 
 
@@ -667,7 +717,7 @@ gst_clock_id_unschedule (GstClockID id)
  * GstClock abstract base class implementation
  */
 #define gst_clock_parent_class parent_class
-G_DEFINE_ABSTRACT_TYPE (GstClock, gst_clock, GST_TYPE_OBJECT);
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstClock, gst_clock, GST_TYPE_OBJECT);
 
 static void
 gst_clock_class_init (GstClockClass * klass)
@@ -712,8 +762,6 @@ gst_clock_class_init (GstClockClass * klass)
       g_signal_new ("synced", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
       0, NULL, NULL,
       g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
-  g_type_class_add_private (klass, sizeof (GstClockPrivate));
 }
 
 static void
@@ -721,8 +769,7 @@ gst_clock_init (GstClock * clock)
 {
   GstClockPrivate *priv;
 
-  clock->priv = priv =
-      G_TYPE_INSTANCE_GET_PRIVATE (clock, GST_TYPE_CLOCK, GstClockPrivate);
+  clock->priv = priv = gst_clock_get_instance_private (clock);
 
   priv->last_time = 0;
 
@@ -739,11 +786,7 @@ gst_clock_init (GstClock * clock)
   priv->time_index = 0;
   priv->timeout = DEFAULT_TIMEOUT;
   priv->times = g_new0 (GstClockTime, 4 * priv->window_size);
-  priv->times_temp =
-      priv->times + 2 * priv->window_size * sizeof (GstClockTime);
-
-  /* clear floating flag */
-  gst_object_ref_sink (clock);
+  priv->times_temp = priv->times + 2 * priv->window_size;
 }
 
 static void
@@ -1102,7 +1145,7 @@ gst_clock_get_time (GstClock * clock)
  * @internal: a reference internal time
  * @external: a reference external time
  * @rate_num: the numerator of the rate of the clock relative to its
- *            internal time 
+ *            internal time
  * @rate_denom: the denominator of the rate of the clock
  *
  * Adjusts the rate and time of @clock. A rate of 1/1 is the normal speed of
@@ -1116,9 +1159,9 @@ gst_clock_get_time (GstClock * clock)
  * Subsequent calls to gst_clock_get_time() will return clock times computed as
  * follows:
  *
- * <programlisting>
+ * |[
  *   time = (internal_time - internal) * rate_num / rate_denom + external
- * </programlisting>
+ * ]|
  *
  * This formula is implemented in gst_clock_adjust_unlocked(). Of course, it
  * tries to do the integer arithmetic as precisely as possible.
@@ -1157,7 +1200,7 @@ gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime
 
 /**
  * gst_clock_get_calibration:
- * @clock: a #GstClock 
+ * @clock: a #GstClock
  * @internal: (out) (allow-none): a location to store the internal time
  * @external: (out) (allow-none): a location to store the external time
  * @rate_num: (out) (allow-none): a location to store the rate numerator
@@ -1227,22 +1270,22 @@ gst_clock_slave_callback (GstClock * master, GstClockTime time,
 
 /**
  * gst_clock_set_master:
- * @clock: a #GstClock 
- * @master: (allow-none): a master #GstClock 
+ * @clock: a #GstClock
+ * @master: (allow-none): a master #GstClock
  *
  * Set @master as the master clock for @clock. @clock will be automatically
  * calibrated so that gst_clock_get_time() reports the same time as the
- * master clock.  
- * 
+ * master clock.
+ *
  * A clock provider that slaves its clock to a master can get the current
  * calibration values with gst_clock_get_calibration().
  *
  * @master can be %NULL in which case @clock will not be slaved anymore. It will
- * however keep reporting its time adjusted with the last configured rate 
+ * however keep reporting its time adjusted with the last configured rate
  * and time offsets.
  *
- * Returns: %TRUE if the clock is capable of being slaved to a master clock. 
- * Trying to set a master on a clock without the 
+ * Returns: %TRUE if the clock is capable of being slaved to a master clock.
+ * Trying to set a master on a clock without the
  * #GST_CLOCK_FLAG_CAN_SET_MASTER flag will make this function return %FALSE.
  *
  * MT safe.
@@ -1315,7 +1358,7 @@ master_not_synced:
 
 /**
  * gst_clock_get_master:
- * @clock: a #GstClock 
+ * @clock: a #GstClock
  *
  * Get the master clock that @clock is slaved to or %NULL when the clock is
  * not slaved to any master clock.
@@ -1345,8 +1388,70 @@ gst_clock_get_master (GstClock * clock)
 }
 
 /**
+ * gst_clock_id_get_clock:
+ * @id: a #GstClockID
+ *
+ * This function returns the underlying clock.
+ *
+ * Returns: (transfer full) (nullable): a #GstClock or %NULL when the
+ *     underlying clock has been freed.  Unref after usage.
+ *
+ * MT safe.
+ *
+ * Since: 1.16
+ */
+GstClock *
+gst_clock_id_get_clock (GstClockID id)
+{
+  GstClockEntry *entry;
+
+  g_return_val_if_fail (id != NULL, NULL);
+
+  entry = (GstClockEntry *) id;
+  return g_weak_ref_get (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry));
+}
+
+/**
+ * gst_clock_id_uses_clock:
+ * @id: a #GstClockID to check
+ * @clock: a #GstClock to compare against
+ *
+ * This function returns whether @id uses @clock as the underlying clock.
+ * @clock can be NULL, in which case the return value indicates whether
+ * the underlying clock has been freed.  If this is the case, the @id is
+ * no longer usable and should be freed.
+ *
+ * Returns: whether the clock @id uses the same underlying #GstClock @clock.
+ *
+ * MT safe.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_clock_id_uses_clock (GstClockID id, GstClock * clock)
+{
+  GstClockEntry *entry;
+  GstClock *entry_clock;
+  gboolean ret = FALSE;
+
+  g_return_val_if_fail (id != NULL, FALSE);
+  g_return_val_if_fail (clock != NULL, FALSE);
+
+  entry = (GstClockEntry *) id;
+  entry_clock = g_weak_ref_get (GST_CLOCK_ENTRY_CLOCK_WEAK_REF (entry));
+  if (entry_clock == clock)
+    ret = TRUE;
+
+  if (G_LIKELY (entry_clock != NULL))
+    gst_object_unref (entry_clock);
+
+  return ret;
+}
+
+
+/**
  * gst_clock_add_observation:
- * @clock: a #GstClock 
+ * @clock: a #GstClock
  * @slave: a time on the slave
  * @master: a time on the master
  * @r_squared: (out): a pointer to hold the result
@@ -1356,13 +1461,13 @@ gst_clock_get_master (GstClock * clock)
  * are available, a linear regression algorithm is run on the
  * observations and @clock is recalibrated.
  *
- * If this functions returns %TRUE, @r_squared will contain the 
+ * If this functions returns %TRUE, @r_squared will contain the
  * correlation coefficient of the interpolation. A value of 1.0
  * means a perfect regression was performed. This value can
  * be used to control the sampling frequency of the master and slave
  * clocks.
  *
- * Returns: %TRUE if enough observations were added to run the 
+ * Returns: %TRUE if enough observations were added to run the
  * regression algorithm.
  *
  * MT safe.
@@ -1527,8 +1632,7 @@ gst_clock_set_property (GObject * object, guint prop_id,
       priv->window_size = g_value_get_int (value);
       priv->window_threshold = MIN (priv->window_threshold, priv->window_size);
       priv->times = g_renew (GstClockTime, priv->times, 4 * priv->window_size);
-      priv->times_temp =
-          priv->times + 2 * priv->window_size * sizeof (GstClockTime);
+      priv->times_temp = priv->times + 2 * priv->window_size;
       /* restart calibration */
       priv->filling = TRUE;
       priv->time_index = 0;
@@ -1590,7 +1694,6 @@ gst_clock_get_property (GObject * object, guint prop_id,
  *
  * For asynchronous waiting, the GstClock::synced signal can be used.
  *
- *
  * This returns immediately with TRUE if GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC
  * is not set on the clock, or if the clock is already synced.
  *