/** * gst_clock_id_get_time * @id: The #GstClockID to query * * Get the time of the clock ID * * Returns: the time of the given clock id. * * MT safe. */ GstClockTime gst_clock_id_get_time (GstClockID id) { g_return_val_if_fail (id != NULL, GST_CLOCK_TIME_NONE); return GST_CLOCK_ENTRY_TIME ((GstClockEntry *) id); }
EXPORT_C #endif GstClockReturn gst_clock_id_wait_async (GstClockID id, GstClockCallback func, gpointer user_data) { GstClockEntry *entry; GstClock *clock; GstClockReturn res; GstClockClass *cclass; GstClockTime requested; g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR); g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR); entry = (GstClockEntry *) id; requested = GST_CLOCK_ENTRY_TIME (entry); clock = GST_CLOCK_ENTRY_CLOCK (entry); /* can't sync on invalid times */ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested))) goto invalid_time; /* a previously unscheduled entry cannot be scheduled again */ if (G_UNLIKELY (entry->status == GST_CLOCK_UNSCHEDULED)) goto unscheduled; cclass = GST_CLOCK_GET_CLASS (clock); if (G_UNLIKELY (cclass->wait_async == NULL)) goto not_supported; entry->func = func; entry->user_data = user_data; res = cclass->wait_async (clock, entry); return res; /* ERRORS */ invalid_time: { (func) (clock, GST_CLOCK_TIME_NONE, id, user_data); GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "invalid time requested, returning _BADTIME"); return GST_CLOCK_BADTIME; } unscheduled: { GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "entry was unscheduled return _UNSCHEDULED"); return GST_CLOCK_UNSCHEDULED; } not_supported: { GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported"); return GST_CLOCK_UNSUPPORTED; } }
/** * gst_clock_id_compare_func * @id1: A #GstClockID * @id2: A #GstClockID to compare with * * Compares the two #GstClockID instances. This function can be used * as a GCompareFunc when sorting ids. * * Returns: negative value if a < b; zero if a = b; positive value if a > b * * MT safe. */ gint gst_clock_id_compare_func (gconstpointer id1, gconstpointer id2) { GstClockEntry *entry1, *entry2; entry1 = (GstClockEntry *) id1; entry2 = (GstClockEntry *) id2; if (GST_CLOCK_ENTRY_TIME (entry1) > GST_CLOCK_ENTRY_TIME (entry2)) { return 1; } if (GST_CLOCK_ENTRY_TIME (entry1) < GST_CLOCK_ENTRY_TIME (entry2)) { return -1; } return 0; }
static void process_entry_context_unlocked (GstTestClock * test_clock, GstClockEntryContext * ctx) { GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock); GstClockEntry *entry = ctx->clock_entry; if (ctx->time_diff >= 0) GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_OK; else GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_EARLY; if (entry->func != NULL) { GST_OBJECT_UNLOCK (test_clock); entry->func (GST_CLOCK (test_clock), priv->internal_time, entry, entry->user_data); GST_OBJECT_LOCK (test_clock); } gst_test_clock_remove_entry (test_clock, entry); if (GST_CLOCK_ENTRY_TYPE (entry) == GST_CLOCK_ENTRY_PERIODIC) { GST_CLOCK_ENTRY_TIME (entry) += GST_CLOCK_ENTRY_INTERVAL (entry); if (entry->func != NULL) gst_test_clock_add_entry (test_clock, entry, NULL); } }
static GstClockReturn gst_test_clock_wait_async (GstClock * clock, GstClockEntry * entry) { GstTestClock *test_clock = GST_TEST_CLOCK (clock); GST_OBJECT_LOCK (test_clock); if (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED) goto was_unscheduled; GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock, "requesting asynchronous clock notification at %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry))); gst_test_clock_add_entry (test_clock, entry, NULL); GST_OBJECT_UNLOCK (test_clock); return GST_CLOCK_OK; /* ERRORS */ was_unscheduled: { GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock, "entry was unscheduled"); GST_OBJECT_UNLOCK (test_clock); return GST_CLOCK_UNSCHEDULED; } }
/** * gst_clock_id_wait: * @id: The #GstClockID to wait on * @jitter: (out) (allow-none): a pointer that will contain the jitter, * can be %NULL. * * 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(). * * 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. * 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 * 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 * unscheduled with gst_clock_id_unschedule(). * * MT safe. */ GstClockReturn gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter) { GstClockEntry *entry; GstClock *clock; GstClockReturn res; GstClockTime requested; GstClockClass *cclass; g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR); entry = (GstClockEntry *) id; requested = GST_CLOCK_ENTRY_TIME (entry); clock = GST_CLOCK_ENTRY_CLOCK (entry); /* can't sync on invalid times */ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested))) goto invalid_time; cclass = GST_CLOCK_GET_CLASS (clock); GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "waiting on clock entry %p", id); /* if we have a wait_jitter function, use that */ if (G_UNLIKELY (cclass->wait == NULL)) goto not_supported; res = cclass->wait (clock, entry, jitter); GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "done waiting entry %p, res: %d (%s)", id, res, gst_clock_return_get_name (res)); if (entry->type == GST_CLOCK_ENTRY_PERIODIC) entry->time = requested + entry->interval; return res; /* ERRORS */ invalid_time: { GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "invalid time requested, returning _BADTIME"); return GST_CLOCK_BADTIME; } not_supported: { GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported"); return GST_CLOCK_UNSUPPORTED; } }
static void gst_test_clock_add_entry (GstTestClock * test_clock, GstClockEntry * entry, GstClockTimeDiff * jitter) { GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock); GstClockTime now; GstClockEntryContext *ctx; now = gst_clock_adjust_unlocked (GST_CLOCK (test_clock), priv->internal_time); if (jitter != NULL) *jitter = GST_CLOCK_DIFF (GST_CLOCK_ENTRY_TIME (entry), now); ctx = g_slice_new (GstClockEntryContext); ctx->clock_entry = GST_CLOCK_ENTRY (gst_clock_id_ref (entry)); ctx->time_diff = GST_CLOCK_DIFF (now, GST_CLOCK_ENTRY_TIME (entry)); priv->entry_contexts = g_list_insert_sorted (priv->entry_contexts, ctx, gst_clock_entry_context_compare_func); g_cond_broadcast (&priv->entry_added_cond); }
/** * gst_clock_id_wait_async: * @id: a #GstClockID to wait on * @func: The callback function * @user_data: User data passed in the callback * @destroy_data: #GDestroyNotify for user_data * * Register a callback on the given #GstClockID @id with the given * function and user_data. When passing a #GstClockID with an invalid * time to this function, the callback will be called immediately * with a time set to GST_CLOCK_TIME_NONE. The callback will * be called when the time of @id has been reached. * * The callback @func can be invoked from any thread, either provided by the * core or from a streaming thread. The application should be prepared for this. * * Returns: the result of the non blocking wait. * * MT safe. */ GstClockReturn gst_clock_id_wait_async (GstClockID id, GstClockCallback func, gpointer user_data, GDestroyNotify destroy_data) { GstClockEntry *entry; GstClock *clock; GstClockReturn res; GstClockClass *cclass; GstClockTime requested; g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR); g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR); entry = (GstClockEntry *) id; requested = GST_CLOCK_ENTRY_TIME (entry); clock = GST_CLOCK_ENTRY_CLOCK (entry); /* can't sync on invalid times */ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested))) goto invalid_time; cclass = GST_CLOCK_GET_CLASS (clock); if (G_UNLIKELY (cclass->wait_async == NULL)) goto not_supported; entry->func = func; entry->user_data = user_data; entry->destroy_data = destroy_data; res = cclass->wait_async (clock, entry); return res; /* ERRORS */ invalid_time: { (func) (clock, GST_CLOCK_TIME_NONE, id, user_data); GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "invalid time requested, returning _BADTIME"); return GST_CLOCK_BADTIME; } not_supported: { GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported"); return GST_CLOCK_UNSUPPORTED; } }
static void gst_test_clock_unschedule (GstClock * clock, GstClockEntry * entry) { GstTestClock *test_clock = GST_TEST_CLOCK (clock); GST_OBJECT_LOCK (test_clock); GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock, "unscheduling requested clock notification at %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry))); GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_UNSCHEDULED; gst_test_clock_remove_entry (test_clock, entry); GST_OBJECT_UNLOCK (test_clock); }
static GstClockReturn gst_test_clock_wait (GstClock * clock, GstClockEntry * entry, GstClockTimeDiff * jitter) { GstTestClock *test_clock = GST_TEST_CLOCK (clock); GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock); GST_OBJECT_LOCK (test_clock); GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock, "requesting synchronous clock notification at %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry))); if (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED) goto was_unscheduled; if (gst_test_clock_lookup_entry_context (test_clock, entry) == NULL) gst_test_clock_add_entry (test_clock, entry, jitter); GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_BUSY; while (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_BUSY) g_cond_wait (&priv->entry_processed_cond, GST_OBJECT_GET_LOCK (test_clock)); GST_OBJECT_UNLOCK (test_clock); return GST_CLOCK_ENTRY_STATUS (entry); /* ERRORS */ was_unscheduled: { GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock, "entry was unscheduled"); GST_OBJECT_UNLOCK (test_clock); return GST_CLOCK_UNSCHEDULED; } }
/* Method: time * Returns: the requested time of the entry, in nanoseconds. */ static VALUE rg_time (VALUE self) { return ULL2NUM (GST_CLOCK_ENTRY_TIME (RGST_CLOCK_ENTRY (self))); }
/** * gst_clock_id_wait * @id: The #GstClockID to wait on * @jitter: A pointer that will contain the jitter, can be %NULL. * * 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(). * * 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. * 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 * 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 * unscheduled with gst_clock_id_unschedule(). * * MT safe. */ GstClockReturn gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter) { GstClockEntry *entry; GstClock *clock; GstClockReturn res; GstClockTime requested; GstClockClass *cclass; g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR); entry = (GstClockEntry *) id; requested = GST_CLOCK_ENTRY_TIME (entry); clock = GST_CLOCK_ENTRY_CLOCK (entry); /* can't sync on invalid times */ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested))) goto invalid_time; cclass = GST_CLOCK_GET_CLASS (clock); GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "waiting on clock entry %p", id); /* if we have a wait_jitter function, use that */ if (G_LIKELY (cclass->wait_jitter)) { res = cclass->wait_jitter (clock, entry, jitter); } else { /* check if we have a simple _wait function otherwise. The function without * the jitter arg is less optimal as we need to do an additional _get_time() * which is not atomic with the _wait() and a typical _wait() function does * yet another _get_time() anyway. */ if (G_UNLIKELY (cclass->wait == NULL)) goto not_supported; if (jitter) { GstClockTime now = gst_clock_get_time (clock); /* jitter is the diff against the clock when this entry is scheduled. Negative * values mean that the entry was in time, a positive value means that the * entry was too late. */ *jitter = GST_CLOCK_DIFF (requested, now); } res = cclass->wait (clock, entry); } GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "done waiting entry %p, res: %d", id, res); if (entry->type == GST_CLOCK_ENTRY_PERIODIC) entry->time = requested + entry->interval; if (G_UNLIKELY (clock->stats)) gst_clock_update_stats (clock); return res; /* ERRORS */ invalid_time: { GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "invalid time requested, returning _BADTIME"); return GST_CLOCK_BADTIME; } not_supported: { GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "clock wait is not supported"); return GST_CLOCK_UNSUPPORTED; } }