static gboolean gst_direct_control_binding_get_value_array (GstControlBinding * _self, GstClockTime timestamp, GstClockTime interval, guint n_values, gpointer values_) { GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self); gint i; gdouble *src_val; gboolean res = FALSE; GstDirectControlBindingConvertValue convert; gint byte_size; guint8 *values = (guint8 *) values_; g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE); g_return_val_if_fail (values, FALSE); g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE); convert = self->convert_value; byte_size = self->byte_size; src_val = g_new0 (gdouble, n_values); if ((res = gst_control_source_get_value_array (self->cs, timestamp, interval, n_values, src_val))) { for (i = 0; i < n_values; i++) { /* we will only get NAN for sparse control sources, such as triggers */ if (!isnan (src_val[i])) { convert (self, src_val[i], (gpointer) values); } else { GST_LOG ("no control value for property %s at index %d", _self->name, i); } values += byte_size; } } else { GST_LOG ("failed to get control value for property %s at ts %" GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp)); } g_free (src_val); return res; }
static gboolean gst_direct_control_binding_get_g_value_array (GstControlBinding * _self, GstClockTime timestamp, GstClockTime interval, guint n_values, GValue * values) { GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self); gint i; gdouble *src_val; gboolean res = FALSE; GType type; GstDirectControlBindingConvertGValue convert; g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE); g_return_val_if_fail (values, FALSE); g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE); convert = self->convert_g_value; type = G_PARAM_SPEC_VALUE_TYPE (_self->pspec); src_val = g_new0 (gdouble, n_values); if ((res = gst_control_source_get_value_array (self->cs, timestamp, interval, n_values, src_val))) { for (i = 0; i < n_values; i++) { /* we will only get NAN for sparse control sources, such as triggers */ if (!isnan (src_val[i])) { g_value_init (&values[i], type); convert (self, src_val[i], &values[i]); } else { GST_LOG ("no control value for property %s at index %d", _self->name, i); } } } else { GST_LOG ("failed to get control value for property %s at ts %" GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp)); } g_free (src_val); return res; }
static gboolean gst_direct_control_binding_sync_values (GstControlBinding * _self, GstObject * object, GstClockTime timestamp, GstClockTime last_sync) { GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self); gdouble src_val; gboolean ret; g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), FALSE); g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE); GST_LOG_OBJECT (object, "property '%s' at ts=%" GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp)); ret = gst_control_source_get_value (self->cs, timestamp, &src_val); if (G_LIKELY (ret)) { GST_LOG_OBJECT (object, " new value %lf", src_val); /* always set the value for first time, but then only if it changed * this should limit g_object_notify invocations. * FIXME: can we detect negative playback rates? */ if ((timestamp < last_sync) || (src_val != self->last_value)) { GValue *dst_val = &self->cur_value; GST_LOG_OBJECT (object, " mapping %s to value of type %s", _self->name, G_VALUE_TYPE_NAME (dst_val)); /* run mapping function to convert gdouble to GValue */ self->convert_g_value (self, src_val, dst_val); /* we can make this faster * http://bugzilla.gnome.org/show_bug.cgi?id=536939 */ g_object_set_property ((GObject *) object, _self->name, dst_val); self->last_value = src_val; } } else { GST_DEBUG_OBJECT (object, "no control value for param %s", _self->name); } return (ret); }
static GValue * gst_direct_control_binding_get_value (GstControlBinding * _self, GstClockTime timestamp) { GstDirectControlBinding *self = GST_DIRECT_CONTROL_BINDING (_self); GValue *dst_val = NULL; gdouble src_val; g_return_val_if_fail (GST_IS_DIRECT_CONTROL_BINDING (self), NULL); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), NULL); g_return_val_if_fail (GST_CONTROL_BINDING_PSPEC (self), FALSE); /* get current value via control source */ if (gst_control_source_get_value (self->cs, timestamp, &src_val)) { dst_val = g_new0 (GValue, 1); g_value_init (dst_val, G_PARAM_SPEC_VALUE_TYPE (_self->pspec)); self->convert_g_value (self, src_val, dst_val); } else { GST_LOG ("no control value for property %s at ts %" GST_TIME_FORMAT, _self->name, GST_TIME_ARGS (timestamp)); } return dst_val; }
static GObject * gst_direct_control_binding_constructor (GType type, guint n_construct_params, GObjectConstructParam * construct_params) { GstDirectControlBinding *self; self = GST_DIRECT_CONTROL_BINDING (G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_params, construct_params)); if (GST_CONTROL_BINDING_PSPEC (self)) { GType type, base; base = type = G_PARAM_SPEC_VALUE_TYPE (GST_CONTROL_BINDING_PSPEC (self)); g_value_init (&self->cur_value, type); while ((type = g_type_parent (type))) base = type; GST_DEBUG (" using type %s", g_type_name (base)); /* select mapping function */ switch (base) { case G_TYPE_INT: self->convert_g_value = convert_g_value_to_int; self->convert_value = convert_value_to_int; self->byte_size = sizeof (gint); break; case G_TYPE_UINT: self->convert_g_value = convert_g_value_to_uint; self->convert_value = convert_value_to_uint; self->byte_size = sizeof (guint); break; case G_TYPE_LONG: self->convert_g_value = convert_g_value_to_long; self->convert_value = convert_value_to_long; self->byte_size = sizeof (glong); break; case G_TYPE_ULONG: self->convert_g_value = convert_g_value_to_ulong; self->convert_value = convert_value_to_ulong; self->byte_size = sizeof (gulong); break; case G_TYPE_INT64: self->convert_g_value = convert_g_value_to_int64; self->convert_value = convert_value_to_int64; self->byte_size = sizeof (gint64); break; case G_TYPE_UINT64: self->convert_g_value = convert_g_value_to_uint64; self->convert_value = convert_value_to_uint64; self->byte_size = sizeof (guint64); break; case G_TYPE_FLOAT: self->convert_g_value = convert_g_value_to_float; self->convert_value = convert_value_to_float; self->byte_size = sizeof (gfloat); break; case G_TYPE_DOUBLE: self->convert_g_value = convert_g_value_to_double; self->convert_value = convert_value_to_double; self->byte_size = sizeof (gdouble); break; case G_TYPE_BOOLEAN: self->convert_g_value = convert_g_value_to_boolean; self->convert_value = convert_value_to_boolean; self->byte_size = sizeof (gboolean); break; case G_TYPE_ENUM: self->convert_g_value = convert_g_value_to_enum; self->convert_value = convert_value_to_enum; self->byte_size = sizeof (gint); break; default: GST_WARNING ("incomplete implementation for paramspec type '%s'", G_PARAM_SPEC_TYPE_NAME (GST_CONTROL_BINDING_PSPEC (self))); GST_CONTROL_BINDING_PSPEC (self) = NULL; break; } } return (GObject *) self; }
/** * gst_control_binding_get_g_value_array: * @binding: the control binding * @timestamp: the time that should be processed * @interval: the time spacing between subsequent values * @n_values: the number of values * @values: array to put control-values in * * Gets a number of #GValues for the given controlled property starting at the * requested time. The array @values need to hold enough space for @n_values of * #GValue. * * This function is useful if one wants to e.g. draw a graph of the control * curve or apply a control curve sample by sample. * * Returns: %TRUE if the given array could be filled, %FALSE otherwise */ gboolean gst_control_binding_get_g_value_array (GstControlBinding * binding, GstClockTime timestamp, GstClockTime interval, guint n_values, GValue * values) { GstControlBindingClass *klass; gboolean ret = FALSE; g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), FALSE); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE); g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), FALSE); g_return_val_if_fail (values, FALSE); klass = GST_CONTROL_BINDING_GET_CLASS (binding); if (G_LIKELY (klass->get_g_value_array != NULL)) { ret = klass->get_g_value_array (binding, timestamp, interval, n_values, values); } else { guint i; GType type, base; base = type = G_PARAM_SPEC_VALUE_TYPE (GST_CONTROL_BINDING_PSPEC (binding)); while ((type = g_type_parent (type))) base = type; GST_INFO_OBJECT (binding, "missing get_g_value_array implementation, we're " "emulating it"); switch (base) { case G_TYPE_INT: CONVERT_ARRAY (int, INT); break; case G_TYPE_UINT: CONVERT_ARRAY (uint, UINT); break; case G_TYPE_LONG: CONVERT_ARRAY (long, LONG); break; case G_TYPE_ULONG: CONVERT_ARRAY (ulong, ULONG); break; case G_TYPE_INT64: CONVERT_ARRAY (int64, INT64); break; case G_TYPE_UINT64: CONVERT_ARRAY (uint64, UINT64); break; case G_TYPE_FLOAT: CONVERT_ARRAY (float, FLOAT); break; case G_TYPE_DOUBLE: CONVERT_ARRAY (double, DOUBLE); break; case G_TYPE_BOOLEAN: CONVERT_ARRAY (boolean, BOOLEAN); break; case G_TYPE_ENUM: { gint *v = g_new (gint, n_values); ret = gst_control_binding_get_value_array (binding, timestamp, interval, n_values, v); if (ret) { for (i = 0; i < n_values; i++) { g_value_init (&values[i], type); g_value_set_enum (&values[i], v[i]); } } g_free (v); } break; default: GST_WARNING ("incomplete implementation for paramspec type '%s'", G_PARAM_SPEC_TYPE_NAME (GST_CONTROL_BINDING_PSPEC (binding))); GST_CONTROL_BINDING_PSPEC (binding) = NULL; break; } } return ret; }
static GObject * gstbt_direct_control_binding_constructor (GType type, guint n_construct_params, GObjectConstructParam * construct_params) { GstBtDirectControlBinding *self; self = GSTBT_DIRECT_CONTROL_BINDING (G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_params, construct_params)); if (GST_CONTROL_BINDING_PSPEC (self)) { GType type, base; base = type = G_PARAM_SPEC_VALUE_TYPE (GST_CONTROL_BINDING_PSPEC (self)); g_value_init (&self->cur_value, type); while ((type = g_type_parent (type))) base = type; GST_DEBUG (" using type %s", g_type_name (base)); /* select mapping function */ #define SET_CONVERT_FUNCTION(type) \ if (self->ABI.abi.want_absolute) { \ self->convert_g_value = abs_convert_g_value_to_##type; \ self->convert_value = abs_convert_value_to_##type; \ } \ else { \ self->convert_g_value = convert_g_value_to_##type; \ self->convert_value = convert_value_to_##type; \ } \ self->byte_size = sizeof (g##type); switch (base) { case G_TYPE_INT: SET_CONVERT_FUNCTION (int); break; case G_TYPE_UINT: SET_CONVERT_FUNCTION (uint); break; case G_TYPE_LONG: SET_CONVERT_FUNCTION (long); break; case G_TYPE_ULONG: SET_CONVERT_FUNCTION (ulong); break; case G_TYPE_INT64: SET_CONVERT_FUNCTION (int64); break; case G_TYPE_UINT64: SET_CONVERT_FUNCTION (uint64); break; case G_TYPE_FLOAT: SET_CONVERT_FUNCTION (float); break; case G_TYPE_DOUBLE: SET_CONVERT_FUNCTION (double); break; case G_TYPE_BOOLEAN: self->convert_g_value = convert_g_value_to_boolean; self->convert_value = convert_value_to_boolean; self->byte_size = sizeof (gboolean); break; case G_TYPE_ENUM: self->convert_g_value = convert_g_value_to_enum; self->convert_value = convert_value_to_enum; self->byte_size = sizeof (gint); break; default: GST_WARNING ("incomplete implementation for paramspec type '%s'", G_PARAM_SPEC_TYPE_NAME (GST_CONTROL_BINDING_PSPEC (self))); GST_CONTROL_BINDING_PSPEC (self) = NULL; break; } } return (GObject *) self; }