G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstTimedValueControlSource,
gst_timed_value_control_source, GST_TYPE_CONTROL_SOURCE, _do_init);
+
+enum
+{
+ VALUE_CHANGED_SIGNAL,
+ VALUE_ADDED_SIGNAL,
+ VALUE_REMOVED_SIGNAL,
+ LAST_SIGNAL
+};
+
+static guint gst_timed_value_control_source_signals[LAST_SIGNAL] = { 0 };
+
/*
* gst_control_point_free:
* @prop: the object to free
g_slice_free (GstControlPoint, cp);
}
+static gpointer
+gst_control_point_copy (GstControlPoint * boxed)
+{
+ return g_slice_dup (GstControlPoint, boxed);
+}
+
+GType
+gst_control_point_get_type (void)
+{
+ static volatile gsize type_id = 0;
+
+ if (g_once_init_enter (&type_id)) {
+ GType tmp =
+ g_boxed_type_register_static (g_intern_static_string
+ ("GstControlPoint"),
+ (GBoxedCopyFunc) gst_control_point_copy,
+ (GBoxedFreeFunc) gst_control_point_free);
+ g_once_init_leave (&type_id, tmp);
+ }
+
+ return type_id;
+}
+
static void
gst_timed_value_control_source_reset (GstTimedValueControlSource * self)
{
self, GstClockTime timestamp, const gdouble value)
{
GSequenceIter *iter;
+ GstControlPoint *cp;
- /* check if a control point for the timestamp already exists */
+ g_mutex_lock (&self->lock);
+ /* check if a control point for the timestamp already exists */
/* iter contains the iter right *after* timestamp */
if (G_LIKELY (self->values)) {
iter =
/* If the timestamp is the same just update the control point value */
if (cp->timestamp == timestamp) {
+
/* update control point */
cp->value = value;
+ g_mutex_unlock (&self->lock);
+
+ g_signal_emit (self,
+ gst_timed_value_control_source_signals[VALUE_CHANGED_SIGNAL], 0,
+ cp);
goto done;
}
}
}
/* sort new cp into the prop->values list */
- g_sequence_insert_sorted (self->values, _make_new_cp (self, timestamp,
- value), (GCompareDataFunc) gst_control_point_compare, NULL);
+ cp = _make_new_cp (self, timestamp, value);
+ g_sequence_insert_sorted (self->values, cp,
+ (GCompareDataFunc) gst_control_point_compare, NULL);
self->nvalues++;
+ g_mutex_unlock (&self->lock);
+
+ g_signal_emit (self,
+ gst_timed_value_control_source_signals[VALUE_ADDED_SIGNAL], 0, cp);
done:
self->valid_cache = FALSE;
g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
- g_mutex_lock (&self->lock);
gst_timed_value_control_source_set_internal (self, timestamp, value);
- g_mutex_unlock (&self->lock);
return TRUE;
}
GST_WARNING ("GstTimedValued with invalid timestamp passed to %s",
GST_FUNCTION);
} else {
- g_mutex_lock (&self->lock);
gst_timed_value_control_source_set_internal (self, tv->timestamp,
tv->value);
- g_mutex_unlock (&self->lock);
res = TRUE;
}
}
{
GSequenceIter *iter;
gboolean res = FALSE;
+ GstControlPoint *cp = NULL;
g_return_val_if_fail (GST_IS_TIMED_VALUE_CONTROL_SOURCE (self), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
if (G_LIKELY (self->values) && (iter =
g_sequence_search (self->values, ×tamp,
(GCompareDataFunc) gst_control_point_find, NULL))) {
- GstControlPoint *cp;
/* Iter contains the iter right after timestamp, i.e.
* we need to get the previous one and check the timestamp
iter = g_sequence_iter_prev (iter);
cp = g_sequence_get (iter);
if (cp->timestamp == timestamp) {
+ cp = g_slice_dup (GstControlPoint, cp);
g_sequence_remove (iter);
self->nvalues--;
self->valid_cache = FALSE;
}
g_mutex_unlock (&self->lock);
+ if (cp) {
+ g_signal_emit (self,
+ gst_timed_value_control_source_signals[VALUE_REMOVED_SIGNAL], 0, cp);
+ g_slice_free (GstControlPoint, cp);
+ }
+
return res;
}
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
//GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
+ /**
+ * GstTimedValueControlSource::value-changed
+ * @self: The #GstTimedValueControlSource on which a #GstTimedValue has changed
+ * @timed_value: The #GstTimedValue where the value changed
+ *
+ * Emited right after the new value has been set on @timed_signals
+ *
+ * Since 1.6
+ */
+ gst_timed_value_control_source_signals[VALUE_CHANGED_SIGNAL] =
+ g_signal_new ("value-changed", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST, 0, NULL,
+ NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
+ gst_control_point_get_type ());
+
+ /**
+ * GstTimedValueControlSource::value-added
+ * @self: The #GstTimedValueControlSource into which a #GstTimedValue has been
+ * added
+ * @timed_value: The newly added #GstTimedValue
+ *
+ * Emited right after the new value has been added to @self
+ *
+ * Since 1.6
+ */
+ gst_timed_value_control_source_signals[VALUE_ADDED_SIGNAL] =
+ g_signal_new ("value-added", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST, 0, NULL,
+ NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
+ gst_control_point_get_type ());
+
+ /**
+ * GstTimedValueControlSource::value-removed
+ * @self: The #GstTimedValueControlSource from which a #GstTimedValue has been
+ * removed
+ * @timed_value: The removed #GstTimedValue
+ *
+ * Emited when @timed_value is removed from @self
+ *
+ * Since 1.6
+ */
+ gst_timed_value_control_source_signals[VALUE_REMOVED_SIGNAL] =
+ g_signal_new ("value-removed", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST, 0, NULL,
+ NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
+ gst_control_point_get_type ());
+
+
gobject_class->finalize = gst_timed_value_control_source_finalize;
}