+ GST_WARNING_OBJECT (binding, "missing get_value_array implementation");
+ }
+ return ret;
+}
+
+#define CONVERT_ARRAY(type,TYPE) \
+{ \
+ g##type *v = g_new (g##type,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], G_TYPE_##TYPE); \
+ g_value_set_##type (&values[i], v[i]); \
+ } \
+ } \
+ g_free (v); \
+}
+
+/**
+ * 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 length=n_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;
+ }